How does ASP.Net MVC ActionLink Work? - asp.net-mvc

I am trying to write my own LightWeight MVC for .Net 2.0 using NHaml as the view engine.
In ASP.Net 3.5 MVC the View file we used to specify the link by the code snippet.
Html.ActionLink("Add Product","Add");
In MVC binary there is no function to match this call.
I Only found:
(In class System.Web.Mvc.Html.LinkExtensions )
public static string ActionLink(this System.Web.Mvc.HtmlHelper htmlHelper,
string linkText, string actionName)
There are more similar static classes like FormExtensions, InputExtensions etc.
How does ASP.Net MVC handle it? Does it generates dynamic code for Html.ActionLink?

The ActionLink method is an extension method (hence the this before the type of the first parameter). This means you can use this method as an instance method on all HtmlHelper instances, even though it is not defined on HtmlHelper.
Html is a property on the View of type HtmlHelper. This means you can use the ActionLink extensionmethod on it.
The ActionLink method itself does nothing more than generate a link string (with regards to its arguments) and return that string.

Have you checked out the code on Codeplex? The MVC Framwork is open source, so you can dig around as much as you need to.

Related

Custom HtmlHelper extension method usage problem in asp.net mvc razor

I have converted my classic asp.net mvc views to razor. In a view there is a usage of an extension method (it has overloads) of HtmlHelper:
#Html.CustomAction<AccountController, LogOnModel>("displayText", x => x.Register())
And CustomAction signature is:
public static HtmlString CustomAction<TController, TModel>(this HtmlHelper<TModel> view, string displayText, Expression<Func<TController, object>> where TController : Controller
I have also enabled view compilation at build time (through .proj file). When I build the project I get these errors pointing to that line:
Argument 1: cannot convert from
'method group' to
'System.Web.WebPages.HelperResult'
The best overloaded method match for
'System.Web.WebPages.WebPageExecutingBase.Write(System.Web.WebPages.HelperResult)'
has some invalid arguments
What is the reason of these errors? How can I correct it?
The Razor parser sees < and thinks it's an HTML tag. Therefore, it only parses Html.CustomAction as the expression.
You need to wrap the call in parentheses to force it to treat the entire call as a single expression:
#(Html.CustomAction<AccountController, LogOnModel>("displayText", x => x.Register()))

Accessing Model object in a custom Html helper

I'm trying to create a custom HTML helper and I would like to know how I can access the Model object without passing it as a parameter.
Thanks
If you are using strongly typed views which you should:
public static MvcHtmlString MyHelper<TModel>(this HtmlHelper<TModel> htmlHelper)
{
TModel model = htmlHelper.ViewData.Model;
return MvcHtmlString.Empty;
}
If you are not using strongly typed views which you shouldn't:
public static MvcHtmlString MyHelper(this HtmlHelper htmlHelper)
{
object model = htmlHelper.ViewData.Model;
return MvcHtmlString.Empty;
}
HTML helpers are a bad way to generate HTML programmatically. Web Forms is much better with code in a page class file and HTML markup in a separate file. Yes HTML helpers put some code in separate class files but you are calling code from your HTML page. Whats to stop you from writing code directly in your view page. MVC is supportive of lots of bad practices which you don't have to do but for some reason in Web Forms developers have to do bad practices because it is allowed. If you learn Web Forms well, you will develop maintainable and scalable web applications using modern object oriented patterns instead of procedural logic like HTML helpers.

Url.Action is member of..?

Url.Action found in MVC is member of what classes? VS2008 cannot find it and keeps offering me just System.Security.Policy to import. Alternatively, can I make ActionLink helper NOT to encode it's content, so this code would work:
sb.Append(helper.ActionLink(linkText, actionName, controllerName, new{onclick=""}));
System.Web.Mvc.UrlHelper
Please see System.Web.Mvc.UrlHelper (found in System.Web.Mvc.dll):
Contains methods for building URLs for
ASP.NET MVC within your application.

Given htmlHelper + action name, how to figure out controller name?

How does HtmlHelper.ActionLink(htmlhelper,string linktext,string action) figures out correct route?
If i have this=>
HtmlHelper.ActionLink("Edit","Edit")
Mvc automatically finds out correct route.
i.e. - if controller was Product, it will render anchor with href product/edit.
So - how to figure out controller name when i got htmlHelper + action name combo?
If your HtmlHelper looks something like:
public static string MyHelper(this HtmlHelper htmlHelper,
... some more parameters ...) {
return ... some stuff ...
}
Then from your helper, access:
RouteData routeData = htmlHelper.ViewContext.RouteData;
string controller = routeData.GetRequiredString("controller");
The RouteData object contains all the values that were processed by ASP.NET Routing for the current request. This will include the parameter names and values from the route, such as "{controller}/{action}/{id}". Many of the built-in ASP.NET MVC helpers grab "ambient" data from there so that the developer doesn't have to type them in for every helper they use.
You can also download the full source code to ASP.NET MVC from here:
ASP.NET MVC 1.0 RTM source code
ASP.NET MVC 2 Release Candidate source code

Converting classic ASP.NET custom control to MVC

Ok, this is for me a very tough challenge. We're taking our existing ASP.NET website and converting (redesigning the PL only) to MVC. Our site is very complex. But the hard part is to convert the existing custom controls to MVC equivilant. The custom controls (I am not talking about user controls) are just of course a class currently that inherits System.Web.UI.Control and uses that object throughout. For example, we have some properties at the top of this existing custom class like so:
Dictionary<int, Control> configControls;
DropDownList kControl;
CheckBox confirmBox;
These all are variables of type Web controls in classic ASP.NET.
So I figured maybe what I could do (without building entire new custom controls from scratch) is to use the HtmlHelper object. So I tried this:
(include first the using statement that includes System.Web.MVC.Html at the top of my new custom class in our new web project)
private HtmlHelper helper;
Dictionary configControls;
helper.DropDownList
but this is not working. I guess I can't use this object just like this ?? I figured I can use HtmlHelper in the Dictionary and then make variable types off of helper. but those are just extension methods, not objects
I don't know of an equivalent to something like the generic "Control" we had available to us to inherit from such as in classic ASP.NET. Surely it won't be the same in MVC obviusly (stateless and a completely diff way of doing things) but what can I use in MVC with the same concept sort of?
So I figured maybe what I could do (without building entire new custom controls from scratch) is to use the HtmlHelper object. So I tried this:
(include first the using statement that includes System.Web.MVC.Html at the top of my new custom class in our new web project)
private HtmlHelper helper;
Dictionary configControls;
helper.DropDownList
but this is not working. I don't even know if this approach will work in my custom control. And when I try to use my helper variable, I get no extension methods unless it's inside an existing extension method where the signature has an HtmlHelper param passed in. So when I create that private variable just in my custom class outside, I get nothing in intellisense to choose from when doing "helper.". So do I need to define that object like this: ?
private HtmlHelper htmlHelper = new HtmlHelper();
but it's asking for a ViewContext and an IViewDataContainer as params. If I'm building out a custom method that knows nothing yet about its view (it shouldn't need to) because I'm simply creating strings of HMTL in this custom class to be passed to the Extension method to ultimately spit out fields then maybe I can't use HtmlHelper this way in a custom class like this.
So can I use that object in a way instead of "Control"? Maybe I can even in my dictionary variable use type object in place of control ? I don't know and then cast object to type HtmlHelper when I need to use or reference that value from the dictionary? But for now, I figured I can use HtmlHelper object in the Dictionary and then make variable types off of helper. but those are just extension methods, not objects.
I hope I am making any sense here when you read this.
I just blogged about this last night, some of this might be helpful for you.
WebForms And MVC In Harmony — Almost…
Basically it discusses some options for emulating "WebControls" using MVC.
Additionally, you can still use WebControls like you could before (granted they may not work if they need things like the ViewState). The problem I've discovered with that is you have a disconnect from the inline render code and the WebControls themselves.
I did write this method last night which let you use WebControls with inline code.
using System.Reflection;
using System.IO;
using System.Web.UI;
using System.Web;
using System.Web.Mvc;
public static class MyExtensionMethods {
//example method - renders a webcontrol to the page
public static void RenderControl(this HtmlHelper helper, Control control) {
//perform databinding if needed
MethodInfo bind = control.GetType().GetMethod("DataBind");
if (bind is System.Reflection.MethodInfo) {
bind.Invoke(control, null);
}
//render the HTML for this control
StringWriter writer = new StringWriter();
HtmlTextWriter html = new HtmlTextWriter(writer);
control.RenderControl(html);
//write the output
HttpContext.Current.Response.Write(writer.ToString());
//and cleanup the writers
html.Dispose();
writer.Dispose();
}
}
//then used like...
<% int[] numbers = { 1, 2, 3, 4, 5 }; %>
<% this.Html.RenderControl(new DataGrid() { DataSource = numbers }); %>
Just an interesting concept you might be interested in.
Short of hacking webforms controls into your MVC application, servercontrols with many methods do not map to MVC.
They are replaced by partials and controllers(or subcontrollers if you like that sort of thing).
If all you want to do is render some HTML based on a few parameters, then a Helper is what you are after. Static Class, static methods. If however, you need to keep state, and do a bunch of stateful stuff, then a partial, JS, and controller(or subcontroller) are really what you are after.
Server Controls that manage their own state really are a thing of the past in MVC.
Remember that MVC is an attempt to use the web the way it was meant to work, particularly if you bring REST into the picture. Webforms is a fudge to make the web work like windows forms.
I would create needed business logic, shared partial view (probably, with quite a lot of well structured javascript lines attached) and seperated controller.
Then i would use this bunch of code through partial request technique.
Not sure how much this will be of help but, do have a look at this series of blog post
Custom controls everywhere
Also have a look at the Catharsis project
Web-Application Framework - Catharsis - Part I - New Solution
The codeplex URL for the same is
Catharsis
This project has some good examples of control creating for asp.net mvc.

Resources