I had a somewhat crazy idea earlier tonight, and got 3/4 of the way done implementing it and have run in to a weird problem.. I wanted to automatically generate an index of all methods on a controller than return an ActionResult, as well as a simple form for each to sumbmit their valid data.. Seemed like a pretty simple thing to do via reflection:
Quickie ViewModel to hold each reflected action:
public class ReflectedAction
{
public ReflectedAction(MethodInfo methodInfo, string controllerName)
{
this.ActionName = methodInfo.Name;
this.ControllerName = controllerName;
this.Parameters = methodInfo.GetParameters().Select(p => p.Name);
}
public string ControllerName { get; set; }
public string ActionName { get; set; }
public IEnumerable<string> Parameters { get; set; }
}
Action to reflect all the actions on the current controller:
public virtual ActionResult AutoIndex()
{
Type controllerType = this.ControllerContext.Controller.GetType();
string controllerName = controllerType.Name.Replace("Controller", string.Empty);
var methods = this.ControllerContext.Controller.GetType().GetMethods().Where(
m => m.ReturnType.Name.Contains("ActionResult"));
var model = methods.Select(m => new ReflectedAction(m, controllerName));
return View(model);
}
Inside the view, I just wanted to use a simple WebGrid to render out each action as a row, with the first column being the name of the action, and the second column being a mini-form, with the ability to fill out any fields that the action has (I tried doing it as a helper, or inline in the grid format, latter is include here:
@using TfsMvc.Controllers
@model IEnumerable<TestController.ReflectedAction>
@{
ViewBag.Title = "AutoIndex";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>AutoIndex</h2>
@{
var grid = new WebGrid(
source: Model,
ajaxUpdateContainerId: "grid",
defaultSort: "ActionName",
canPage: false);
}
<div id="grid">
@grid.GetHtml(
tableStyle: "grid",
headerStyle: "head",
alternatingRowStyle: "alt",
columns: grid.Columns(
grid.Column("ActionName"),
grid.Column(format: (action) =>
{
using (Html.BeginForm((string)action.ActionName, (string)action.ControllerName, FormMethod.Get))
{
string htmlString = string.Empty;
foreach (string parameter in action.Parameters)
{
htmlString = "<span>" + Html.Label(parameter) + Html.TextBox(parameter) + "</span>";
}
htmlString += "<input type=\"submit\" />";
return new HtmlString(htmlString);
}
}))
)
</div>
The grid appears to render correctly, but the weird part is that all the form html tags render outside the grid, but the controls render inside the grid:
<div id="grid">
<form action="/Test/CloneTestPlan" method="get"></form>
<form action="/Test/ConfigureTestPlan" method="get"></form>
<form action="/Test/EnvConfig" method="get"></form>
<form action="/Test/FixTestLink" method="get"></form>
<!-- ton of other actions snipped-->
<table class="grid">
<thead>
<tr class="head"><th scope="col"><a href="#" onclick="$('#grid').load('/Test/SecretIndex?sort=ActionName&sortdir=DESC&__=634581349851993336 #grid');">ActionName</a></th><th scope="col"></th></tr>
</thead>
<tbody>
<tr><td>CloneTestPlan</td><td><span><label for="subid">subid</label><input id="subid" name="subid" type="text" value="" /></span><input type="submit" /></td></tr>
<tr class="alt"><td>ConfigureTestPlan</td><td><span><label for="apply">apply</label><input id="apply" name="apply" type="text" value="" /></span><input type="submit" /></td></tr>
<tr><td>EnvConfig</td><td><span><label for="create">create</label><input id="create" name="create" type="text" value="" /></span><input type="submit" /></td></tr>
<tr class="alt"><td>FixTestLink</td><td><span><label for="commit">commit</label><input id="commit" name="commit" type="text" value="" /></span><input type="submit" /></td></tr>
<!-- ton of other actions snipped-->
</tbody></table>
</div>
As you can see, the tags render outside of the table! Any idea what I'm doing wrong here? Or can you just not do BeginForm inside a Webgrid? Any better approach for making a bunch of individual forms?
Thanks in advance!
Try rendering the <form>
yourself without using the helper.
It looks like the lambdas are executed inside helper before it spits out the content, which causes the BeginForm
to render to output instantly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With