I am attempting to implement a custom locale service in an MVC 2 webpage. I have an interface IResourceDictionary that provides a couple of methods for accessing resources by culture. This is because I want to avoid the static classes of .Net resources.
The problem is accessing the chosen IResourceDictionary from the views. I have contemplated using the ViewDataDictionary given, creating a base controller from which all my controllers inherits that adds my IResourceDictionary to the ViewData before each action executes.
Then I could call my resource dictionary this way:
(ViewData["Resources"] as IResourceDictionary).GetEntry(params);
Admittedly, this is extremely verbose and ugly, especially in inline code as we are encouraged to use in MVC. Right now I am leaning towards static class access
ResourceDictionary.GetEntry(params);
because it is slightly more elegant. I also thought about adding it to my typed model for each page, which seems more robust than adding it to the ViewData..
What is the preferred way to access my ResourceDictionary from the views? All my views will be using this dictionary.
HtmlHelper extension, which will allow you to call your method like this:
<%: Html.GetEntry(params) %>
Seems a pretty good solution
Related
I am currently working on multiple ASP.NET MVC web apps.
All of these web apps have the same navigation bars/menus.
Some of the menu items are app specific, so they can be passed from the respective app.
Some of the menu items are not app-specific, such as whether user is admin or not, based on which I show an admin link on the nav bar. The logic for getting the admin property is available in the business layer.
Is it possible to make this html helper such that I don't have to pass the non-app specific parameters from the respective apps ?
Can I call the business layer from the html helper ?
Is it advisable ?
I want this html helper or any other solution easily distributable...
Thanks
HTML helpers are extension methods on the System.Web.Mvc.HtmlHelper type that return an System.Web.Mvc.MvcHtmlString object. If you want "easily distributable", then you can create a library project with the helper extensions that you need. Then add the project in as a reference on the MVC project.
#using statements can bring in the extensions to the Razor view. The helper object that you bring in through the extension method in the library will give you access to most of the information available to the Razor view at the time the helper is called (with the ViewContext property).
The extensions can be overloaded as much as needed to account for variations in the projects. Common menu options can be added to the library as a static collection that can be accessed by both the MVC project and the extension methods.
update
MVC is set up such that you can do what you want. You have a lot of control. Your helper can include as much code as you need. It's not like you are "breaking the rules". But best practice dictates that you keep your business logic in the controller. By putting that into the helper, which gets called by the Razor view, you are in effect moving the business logic into the Razor view.
HTML Helpers in general are a lightweight way to create HTML code. Thus they are easy to reuse any you can have dozens or hundreds on a single Razor view. That idea gets broken when you move a bunch of business logic into the helper. Then you have a potential of slowing things down if the helper is to be reused a lot.
Good rule of thumb for MVC, if your helper starts getting complicated, create a partial view. I would probably create a model to represent the menu, then create a partial view in the Shared folder that uses that model, then call it from the parent view. I think that would give you more flexibility, and be more in keeping with the MVC best practices.
Is there any way to look at all the data annotations or attributes available in Asp.net MVC?
i.e. for validation we have "Required", "StringLength" etc, for Action verbs, "HttpPost", "HttpGet" etc, similarly "Bind", "MetadataType" etc.
I am kind of new to Asp.net MVC and MVC is loaded with attributes for different purposes and I don't know if there is an attribute available to do something or even whether to use an attribute to get something done. Is there any documentation of these necessary/helper/nice-to-use attributes?
Look at the classes in System.ComponentModel.DataAnnotations and System.Web.Mvc in Visual Studio's Object Browser.
For some reason the MS documentation is really difficult to find! I came across this post, then ... by chance ... a Jon Galloway video directed me to the following documentation:
System.ComponentModel.DataAnnotations Namespace
This post is 4yrs old, but next time I search I'll find the link here!
For the data annotations, check out this blog post.
For other filters (action filters, authorize filters, etc) I'm not aware of a list anywhere, but according to this article on ASP.net they implement one of four interfaces:
Authorization filters – Implements the IAuthorizationFilter attribute.
Action filters – Implements the IActionFilter attribute.
Result filters – Implements the IResultFilter attribute.
Exception filters – Implements the IExceptionFilter attribute.
The ASP.NET MVC source is available on CodePlex, so you could search it for classes that implement one of those 4 interfaces.
I have a custom class library that performs validation. I want to open up this class for use within Javascript. I understand that I can easily achieve this by utilizing WebServices/WCF or by creating a function on my page with the WebMethod attribute, but it'd be nice not to have to set all that up for every project.
Ideally I'd like to just add the WebMethod attribute to my class library methods and then call them using Javascript.
Unfortunately, you will have to expose an endpoint that your Javascript function can see. In ASP.NET this is most easily done with the web method attribute that you have encountered. However, this method requires two parts the endpoint and the actual code. If you think about it, it makes sense. Javascript has no way of talking directly to a compiled .NET assembly. It must go through a type agnostic interface. One thing that you can do, and you may be doing this, is generate the .asmx file with the web method and then have that call your class library method. This will not prevent you from having the .asmx endpoint, but will prevent any duplication of the actual code. I don't have a lot of experience with WCF, but I believe that you will still need an endpoint of some sort to interface between Javascript and C#.
The WebMethod attribute has to be used from a page level method. It's not too much of a hassle though if you set your library up correctly. A WebMethod is just a static method, but if you plan to use it in multiple pages, then you most definately want to make it a WCF service. Neither of these should be difficult and the overhead is minimal.
Alternatively you could use a base Page class that all your other pages inherit from and define your WebMethod there. This class could live in class library somewhere and be used across multiple projects.
I have just started to learn ASP.NET MVC. When comparing ASP.NET MVC with Web Forms one of the main advantage of MVC is always told to be better support of Unit Testing. Can I got a good explanation of how it has better support?
Edit :
If possible please provide example in both.
Asp.Net MVC has better unit testing support for one main reason - the whole architecture is built to use HttpContextBase, HttpRequestBase and HttpResponseBase.
Asp.Net webforms is dependent on HttpContext.Current, which is a singleton that you have no control over - it is set up and passed to your pages as part of the HttpApplication executing the request. In most cases, in order to get the page to execute correctly, you need to execute it in a real HttpContext. Since many of the properties of HttpContext are not settable (like Request and Response), it is extremely difficult to construct fake requests to send to your page objects.
This makes unit testing webforms pages a nightmare, since it couples all your tests to needing all kinds of context setup.
Contrast that to ASP.Net MVC, where you can mock an HttpContext! Now your code doesn't even need a web server to give it context, you can just set up the bits you need, and hand the mocked context to your method.
The ASP.NET page lifecycle makes it incredibly difficult to unit test classes that derive from Page, which starts out with too many responsibilities and becomes a god object when you add application logic to it. Even worse, it has hidden dependencies on static classes and requires a default parameterless constructor, which limits your ability to inject dependencies.
So, to make an ASP.NET WebForms page testable, you need to take all the logic out of your code-behinds and put it in another class - typically a Presenter as in the Model-View-Presenter pattern.
ASP.NET MVC controllers are already separated from their templates and aren't encumbered by the ASP.NET page lifecycle.
Because you can create a controller object in your unit test, call some actions on it, and see the result right away, then you can Assert.IsBlahBlahBlah(); on it.
For example,
[TestMethod]
public void Index()
{
// Arrange
HomeController controller = new HomeController();
// Act
ViewResult result = controller.Index() as ViewResult;
Assert.IsNotNull(result);
}
With that method, you now know that your Index view is returned from the Home controller.
If you want to use ASP.Net WebForms (like i do) and unit tests together, take a look at this:
WebForms MVP on codeplex
Works for me.
It's far more cumbersome to test a code behind page than to test a controller. With the MVC pattern, there's a more logical separation of presentation logic thus making it easier to write tests.
You can do exactly the same thing with Web Forms, it's just that people who don't know better write code that can't be tested this way.
There's no reason to have business logic in a codebehind class. Same with data access logic. Even right there, that lets you test the parts of the application most subject to both bugs and testing.
Some might say that doesn't allow you to test for button clicks and other user-interface events. If you want to do that, then you can go ahead and create your own MVC or MVP or other such pattern, that does use a separate interface for the user interface actions. Then do exactly the same kind of test you'd do if using ASP.NET MVC.
And you still have the problem of not being able to test client-side code.
Slightly OT but you may want to look at Selenium for Unit Testing webpages....
In reference to Lawrences suggestion about Selenium, there is also WatiN.
This is not specific to MVC, but I think MVC definitely helps in that it keeps element ids and classes clean and easier to target from the test.
With WatiN you can do the following (example from their site).
[Test]
public void SearchForWatiNOnGoogle()
{
using (var browser = new IE("http://www.google.com"))
{
browser.TextField(Find.ByName("q")).TypeText("WatiN");
browser.Button(Find.ByName("btnG")).Click();
Assert.IsTrue(browser.ContainsText("WatiN"));
}
}
I am working on an ASP.NET MVC application that contains a header and menu on each page. The menu and header are dynamic. In other words, the menu items and header information are determined at runtime.
My initial thought is to build a base Controller from which all other controllers derive. In the base controller, I will obtain the menu and header data and insert the required information into the ViewData. Finally, I will use a ViewUserControl to display the header and menu through a master page template.
So, I'm trying to determine the best practice for building such functionality. Also, if this is the recommended approach, which method should I override (I'm guessing Execute) when obtaining the data for insertion into the ViewData.
I'm sure this is a common scenario, so any advice/best-practices would be appreciated! Thanks in advance!
EDIT:
I did find the following resources after posting this (of course), but any additional anecdotes would be awesome!
http://www.singingeels.com/Blogs/Nullable/2008/08/14/How_to_Handle_Side_Content_in_ASPNET_MVC.aspx
How do you use usercontrols in asp.net mvc that display an "island" of data?
Depends on where your information is coming from. We have standard view data that we use to generate some of the information we have on screen that we create in just this fashion. It works well and is easily maintained. We override the View method to implement strongly typed view names and use this information to retrieve some of the data that the master page requires as well.
You could write a helper extension to render the header/menu
That way you could have it show in different places in the view should you need to, but only one place for maintenance.
public static HtmlString MainMenu(this HtmlHelper helper)
Use a base controller class to implement generell filter methods. The controller class implements some filter interfaces IActionFilter, IAuthorizationFilter, IExceptionFilter and IResultFilter which are usefull to implement some common behavior for all controllers.
If the menu data is the same on all pages but different for each unique user.
Generate the menudata in an OnAuthorization or Initialize method of your controller base class. First will be called on authorization. Initialize will be called before every action method. You have access to ViewData Context. Generate the menudata there.
Put the view content for menu and header into the master page and access generated ViewData there.
I tackled a similar design challenge a couple months ago - implementing a breadcrumb feature that changes as user navigates from page to page.
I overrided the OnActionExecuting method to gather the breadcrumbs and store them in ViewData (I use the name of the action as the breadCrumb of the view). Then I updated the Master page to include a user control that takes the ViewData and renders the breadcrumbs.
One thing to be aware is that if you were using the default ASP.NET MVC error handling attribute [HandleError] and your error page is using the same Master page that attempts to read the ViewData, you will soon find out that you can't access ViewData from your error page and it will raise an exception. Depending on whether you need the ViewData for failure scenarios, the viable solution is to use a separate Master page or do this: How do I pass ViewData to a HandleError View?
I'll answer your question with another question. Will the base controller have to determine what type it really is in order to generate the proper menu data? If so, then you're defeating the purpose of polymorphism and the code to generate the data should go in each controller, perhaps in OnActionExecuting if the menu is the same for all actions. Pushing it back down into a parent class seems likely to end up with some switch statement in the parent class doing what each derived controller really ought to take care of.