Razor and Creating Helpers for Users: Html.* - asp.net-mvc-3

I have an ASP.NET MVC3 (with Razor) application where I allow users to specify components for the view -- like the layout, or partials that I use to render content. (For example, I have a model that has a Title and Description, and I allow users to specify a CSHTML partial in a particular directory that I use to render the data.)
The problem that I'm running into is isolation and ease of use for my users. For example, they can currently write code in their partials like:
#Html.ActionLink("edit", "Edit", "Content", new { Id = Model.Id }, null)
I would instead like them to write something like:
#SomeHelper.EditLinkFor(Model.Id)
Right now, my controllers are all part of the public API. Users need to know controller and action names to specify certain links (eg. edit link). I would like to provide a simplified API.
But how do I do it? If I just create the SomeHelper class, trying to call #Html.ActionLink isn't making much progress. I tried writing:
return System.Web.Mvc.Html.LinkExtensions.ActionLink(null, content.Title, "Details", "Content", new { Id = content.Id }, null);
But I get a null pointer exception. Creating an HtmlHelper instance for the first parameter is not easy.
What are my options? Am I stuck with providing them full access to all my controllers as part of my API? Is there no way to provide a simplified API for their consumption? (I'm not trying to block them from writing Razor code; only encapsulate and simplify calls, and eliminate an underlying dependency on my controllers and models.)

There are a few possible options:
a) You can extend the HtmlHelper with your own class
b) Reusing #helpers accross multiple views
c) Change the base type of your views

The html helpers provided are pretty basic - but you certainly can create a helper. Just be careful - the existing API is provided and fits in exactly with the rest of the MVC programming model (Ajax and html helpers and the route syntax)
The problem is in how you call the code. Please post all of your code so we can check it out.
The question is exactly what do you want to do? You want to create a helper for
EditLinkFor - but something is failing, can we see all the code?

Related

Few basic query about ASP.Net MVC

i am new in mvc and learning it by going through wrox book. i encounter few thing and i am looking for good clarification.apologized for asking many question in one shot.
1) #Html.DisplayFor & #Html.EditFor
when we use #Html.DisplayFor then what html control render at client side ?
when we use #Html.EditFor then what html control render at client side ?
2) what ModelState.IsValid does ?
i always see ModelState.IsValid return true ? when it actually return false ?
3) how to extract the form submitted value from ModelState ?
i try to do it this way like ModelState["Name"] or ModelState["Name"].ToString() both gives error.
4) what is Remote Validation in mvc ?
5) when we use html helper to render text boxes then how could i attach multiple attribute with it. i tried this way
i tried to display model text like this way but did not
#Html.LabelFor(m => m.Name, new { #id = "name", #class = "", title = "#m.Name" })
can't we specify or assign model text like this way title = "#m.Name" ? if not then how could i assign a model text to title attribute ?
when we need to use # sign when we work with html controls attribute
6) Is it possible to call different type of function/method directly from view
i like to know that
a) if i have few static function or static classes function then can we call it directly from view ?
b) can we can controller method directly from view ?
c) how to call any generic method directly from view?
d) is it possible to call any action method directly from view ?
e) can we can call any model method directly from view ?
which is possible and which is not please explain with reason and sample code
7) regarding data annotation
i want to work with data annotation but i want data annotation should render different js in page for fancy validation message. how to use different jquery validation plugin with data annotation....where we need to change in code.
please answer all my question point wise with example & sample code for better understanding. thanks
when we use #Html.DisplayFor then what html control render at client side ?
That's totally gonna depend on the specific type of the property you are calling the DisplayFor on. The DisplayFor helper will analyze the specific type of the property used in the expression and invoke the corresponding display template. You could also write custom display templates for your view model types. Brad Wilson wrote a nice blog post about templates that I invite you to go through to better familiarize with the basic concepts: http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html
There are a series of posts, make sure you've read them all.
when we use #Html.EditFor then what html control render at client side ?
That's totally gonna depend on the specific type of the property you are calling the EditorFor on. The EditorFor helper will analyze the specific type of the property used in the expression and invoke the corresponding editor template. You could also write custom editor templates for your view model types. Brad Wilson wrote a nice blog post about templates that I invite you to go through to better familiarize with the basic concepts: http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html
There are a series of posts, make sure you've read them all.
i always see ModelState.IsValid return true ? when it actually return false ?
When there are errors added to the ModelState. Could happen if you have used some data annotations on your view model to do validation and the values submitted to the server failed this validation. Normally it's the default model binder that is adding error messages to the ModelState (making ModelState.IsValid return false) when binding the request values to your view model.
i try to do it this way like ModelState["Name"] or ModelState["Name"].ToString() both gives error.
In ASP.NET MVC you use a view model. Your [HttpPost] controller action takes a view model as parameter which is a class specifically designed to meet the purpose of your view logic. Here's an example of how a typical POST action might look like in ASP.NET MVC:
[HttpPost]
public ActionResult SomeAction(MyViewModel model)
{
if (!ModelState.IsValid)
{
// validation on the view model failed => redisplay the view
// so that the user can fix the errors
return View(model);
}
// At this stage you know that the model has passed validation
// It is here that you would typically map the view model to some domain model(s)
// and pass them to your DAL for some processing.
// Finally when this processing completes redirect (Redirect-After-Get pattern)
return RedirectToAction("Success");
}
4) what is Remote Validation in mvc ?
It's a view model property decorated with the [Remote] attribute which in turn emitted some HTML5 data-* attributes on the corresponding input field. In turn the jquery.validate.unobtrusive.js script will use those properties to send an AJAX request to the corresponding controller action to perform validation before the form is actually submitted. Please feel free to read the corresponding documentation: http://msdn.microsoft.com/en-us/library/gg508808(v=vs.98).aspx
a) if i have few static function or static classes function then can
we call it directly from view ?
No of course not. This question doesn't have any sense. The view doesn't know about any server side specific things other than controller actions. So if you want to call something from a view this something in the ASP.NET MVC world is called a controller action. You could of course us AJAX or something to call it.
b) can we can controller method directly from view ?
Yes, of course, if this controller method returns an ActionResult in which case this controller method has a name: A controller action.
c) how to call any generic method directly from view
Absolutely impossible. That would have been a huge security vulnerability if it was possible. You can only invoke controller actions from a view.
e) can we can call any model method directly from view ?
No, for the Christ sake. I repeat: That would have been a huge seurity vulnerability if it was possible. You can only invoke controller actions from a view.
i want to work with data annotation but i want data annotation should
render different js in page for fancy validation message. how to use
different jquery validation plugin with data annotation....where we
need to change in code.
Sorry, I have strictly no idea what you are asking here. ASP.NET MVC client side validation is tightly coupled with the jquery.validate plugin (whose documentation I invite you to read to better understand its functionality: http://jqueryvalidation.org/documentation/). And if this plugin doesn't meet your requirements, after all, ASP.NET MVC view spits HTML, so feel more than free to use some of the gazillions available javascript validation plugins out there that might fit your specific needs.
Hopefully this answers some of your questions. Next time you post a question on StackOverflow make sure that it is very specific and not asking about the philosophy on the entire world (as you did here). Make your homework, read the documentation, and if you have specific issues, post your code, explain the difficulties you encountered with it, and we will be glad to help.

Strongly typed Razor Views as an Email Template engine

I do know there are several similar questions out there that address this topic, but I am not happy with the answers.
What I'd like is to take full advantage of the Razor View engine that can use strongly typed views with layout pages and partial views. I'd like to declare the model at the top of my views and just pass in that model. So simple! No dynamic models that need to be constructed explicitly just before passing them into the view. EDIT: I'd like to do this outside of a Web application, inside a class library that can construct email bodies. That's the real issue here is making use of the Razor View Engine that is not a web app.
The idea behind this is if I have a User object with 20 properties on it and my first version of the Welcome email only uses the Name, but later I want to edit the template to use their City, State or Email address, then I want to be able to update the Razor view without having to add code and recompile and redeploy.
I see RazorEngine and I love the idea and simplicity, but everything is a dynamic type. My issue here is that I'll be pulling data as models from the database. By having to shove things into a dynamic type, I don't get all my properties on the View.
I also see MvcMailer, which is also nice in theory but it suffers from the same issue which is that all data models passed into the view are dynamic and not strongly typed.
I've begun to build out my own version of this, which will require several web namespaces like System.Web.Mvc, System.Web.Razor and System.Web.WebPages - and I'm okay with that. The issue is the lack of HttpContext and ControllerContext and RouteData .... which I'm trying to mock/stub so the. I'm currently trying to investigate DisplayModes and figure out how to mock these outside a real Web context.
Is there a better way? If you're going to suggest one of the two previously mentioned frameworks, please note my issues and let me know if there are workarounds.
EDIT 2: After playing a bit more with the RazorEngine, the strongly typed models is not necessarily as much of an issue as I thought. What I'm left wishing for now is the ability to use a Layout page and partial views as well. I can hack around this with string placeholders that get replaced, but probably not very efficient AND not very flexible.
Assuming you are trying to achieve this from within an action method of a controller, here's a simple way to do it.
This method will give you the output of a strongly typed view :
public static string RenderViewToString(this Controller controller, string viewName, object model)
{
controller.ViewData.Model = model;
try
{
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindView(controller.ControllerContext, viewName, null);
ViewContext viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(controller.ControllerContext, viewResult.View);
return sw.ToString();
}
}
catch(Exception ex)
{
return ex.ToString();
}
}
Then from within a controller method, all you need to do is call this method with the name of the view and the model.
public ActionResult Mail()
{
// whatever you use to get your User object
var model = new User();
var output = this.RenderViewToString("~/Views/User/Email.cshtml", model)
}
This will allow you to simulate the rendering of a strongly typed view, including its associated layout, and gather the output as a string which you can then use to send via email.
The answer is that it doesn't seem to matter whether the object passed in is dynamic or not. I can pass my strongly typed object, and it will be accepted as is without needing to make it dynamic or rebuild a dynamic object.
My prelim tests show that this should be fine and works well.
Try out Actionmailer.net: https://bitbucket.org/swaj/actionmailer.net/wiki/Home
I've been using it quite successfully.
Check out RazorMachine. It's like RazorEngine, but works with layouts.

Add ASP.NET MVC Routed URLs to view-model objects (for use in JSON)

I'm writing an application which uses ASP.NET MVC with JSON.NET as the server, sending JSON to the client which is read by Knockout and then displayed with data-bindings. This is all working wonderfully, except for one problem:
I have a class Customer which is used to generate a ReviewAuthorViewModel class - the latter is meant specifically for JSON serialization and removes unnecessary fields, circular references, etc. On the client, I want to render a link to the Customer's profile page, with the URL coming from a defined MVC route "user/{username}". Because I'm sending this via JSON, I don't have a .cshtml page in which I can call Url.Action.
The question is: For an arbitrary object, how do I most efficiently/elegantly get a URL for an action with some data, without a .cshtml view?
I'd prefer a solution that doesn't require extra code in each action, but that may be the only choice apart from recreating the routing tables client-side in JavaScript. Below are the things I've already tried, and what was unsatisfactory with each.
Solution Attempt 1
Call the UrlHelper.Action method in the ReviewAuthorViewModel class. However, the UrlHelper requires a request context. For the sake of separation of concerns, I don't want my view model to have a dependency on System.Web.Routing, nor do I want it to need a request context to function.
Solution Attempt 2
Create a class RouteInformation with members Controller, Action, and Data, and an interface IUrlViewModel with two properties, a get of type RouteInformation and a get/set string named Url. The view models needing links then implement this interface, and controllers look for view models of type IUrlViewModel and run UrlHelper.Action with the information from the view model's RouteInformation instance, storing the result in the Url property.
This one works but without reflection I don't know how to find view models implementing IUrlViewModel within other view models, and it feels very kludgy.
Solution Attempt 1 is the OK solution. In asp.net-mvc, view models are part of presentation layer, designed specifically for use with views. You should not worry about having view model depend on asp.net specific things. In fact, they should be coupled, as they should be designed to maximize simplicity of view generation and data exchange between web server and web client. And it's good solution to create separate view model and not use Customer class directly for clients. It wouldn't have been OK if Customer was dependent on Routing.
In fact, you could set that property in controller -
[HttpGet]
public ActionResult Get()
{
var viewModel = new ReviewAuthorViewModel();
viewModel.ProfilePageUrl = Url.Action("Index", "Profile");
// return viewModel;
}

How am I supposed to pass class data to my Views using Codeigniter?

I'm using Codeigniter to build a web app, and I'm trying to follow proper OOP, MVC and Codeigniter convention. A few things are definitely escaping me. Below is a simplified explanation of what's confusing me.
I have a 'companies' table and a Companies_model. This model has private variables like id, name, and url. This model has a method named load_data( $id ), that uses an id to load all the data about a company into the class variables. This $id is coming from the URL. Finally, this model has public getters that return the values.
I have a profile page on my website for every company in my system. In my Companies controller, I load this company's data in the following way.
$this->load->model( 'Companies_model', 'Companies_profile' );
$this->Companies_profile->load_data( $this->uri_company_id );
When my other logic is complete in the controller, I have the following code to render the view:
$this->data['Companies_profile'] = $this->Companies_profile;
$this->load->view( 'profiles/companies_profile_view', $this->data );
In my view, I render data like this:
<p>This company's name is <?php echo $Company_profile->get_name(); ?>.</p>
All of this seems redundant. Why am I passing data to the view when it's already available in a specific instantiation of the Companies_method? I feel confused and that I'm doing something wrong, but I can't figure out what that is. Perhaps I'm not doing anything wrong, but haven't encountered the reason for some of this structure yet. Overall, my app is fairly simple. Can someone shed light on how to properly organize and pass data to views? Why pass the data, and not just make it all available in CI's base class, $this?
NOTE: I have multiple instantiations of the Companies_model on every page I render because I have a list of related companies on each profile page.
That is MVC, at least the way it's done in CodeIgniter. Separation of displaying values from retrieving them from the database. In such simple cases, the advantages are not really visible.
Imagine you later decide to change the database structure. You would only need to rewrite the model to return the same classes and leave front-end code intact. You can also give the view to some web designer to design, without telling him anything about database structure, etc, etc.
One of the main advantages of MVC shows up when you work in teams. Instead of coming up with your own conventions, everyone can do the stuff uniformly.
Passing a class object to he view breaks the idea behind MVC. MVC is designed to break up the parts of programming into 3 aspects. The Model, View and Controller. What you pass to the view are only things that the view needs. The view probably doesn't need the entire object. It probably only needs certain bits of information from the object. It allows you to keep the business logic away from the visual design. It allows a web designer who knows HTML and a little PHP to go in and make changes without having to know how your objects work. he sees.
<?php echo $company_name ?>
which is a lot easier for a non technical person to interpret than
<?php echo $company->getName(); ?>

Is there a way to Iterate all Controllers/Actions in an ASP.NET MVC3 Site?

I'm trying to make a dynamic menu function in an ASP.NET MVC 3 website - and I'd like to know if there is a built-in way to get all of the Controllers and Actions at runtime?
I realize that I can use reflection to find all public methods on my controllers, but this doesn't exactly give me the relative URL that I should put in the <a href="..."> tag.
Also, I'm going to be decorating some of the 'actions' with filter attributes that dictate whether the current user can see/goto those pages. So it would be best if I had access to the filters as well so as to be able to call the IsAccessGranted() method.
What are my options? What is the best option?
I actually just did that two weeks ago.
var q = from type in Assembly.GetExecutingAssembly().GetTypes()
where type.IsClass && type.Namespace != null && type.Namespace.Contains("Controller")
select type;
q.ToList().ForEach(type => doWhatYouNeedToDo(type)));
if you are using T4MVC, then this script will return double entries. To avoid this, work with
&& !type.Name.Contains("T4MVC")
In the method doWhatYouNeedToDo() you could transform the Type object into a DTO that suits your needs and add work further with it.
As far as your dynamic menu is concerned, you could use the MvcSiteMapProvider and implement your own dynamic sitemapprovider with it, so you are no longer bound to the static sitemap xml file.
But reflection is quite slow in .NET, so you might want to store representations of your controllers and method in the database.
There is no built in mechanism in MVC to enumerate over all of your controllers and actions. You would have to use reflection to inspect all the loaded types and look at their methods and the associated attributes. Of course this is assuming that you are using the default reflection-based action dispatching mechanism. Since MVC's pipeline can be replaced in a number of places its easy to inject a system for invoking action methods that is not based on CLR classes and methods. But if you have complete control over your application than you life is easier.
Try TVMVC. You'll still have to use reflection, but the t4 templates will generate a class that's easier to iterate over.

Resources