Best asp.net-mvc questions in October 2010

Does Razor syntax provide a compelling advantage in UI markup?

34 votes

I notice Scott Guthrie is starting to mention Razor a fair bit on his blog but I'm just not that sure that it's a good fit for my style.

Granted it's a fairly unfamiliar style for someone who's pretty used to a "standard" sort of ASP.Net markup (content place holders and inline code), but it just feels like a lot of additional pages to manage and less clear markup to me.

What are other peoples' feelings on it? Is it something that you believe should be seriously considered when scaffolding new MVC pages or is it just trying to solve a problem that doesn't exist?

[Disclaimer: I'm one of the Microsoft developers on MVC and Razor, so I might be a bit biased :)]

We designed Razor to be a concise templating language that uses only the minimal necessary amount of control characters. I would say that large parts of your views can be expressed with fewer characters than the same code using the "traditional" WebForms syntax.

For example the following code snippet in ASPX syntax:

<% if(someCondition) { %>
  <ol>
  <% foreach(var item in Model) { %>
     <li><%: item.ToString() %></li>
  <% } %>
  </ol>
<% } %>

Can be expressed as follows in Razor:

@if(someCondition) {
   <ol>
   @foreach(var item in Model) {
      <li>@item.ToString()</li>
   }
   </ol>
}

While the ASPX version has 21 transition characters (the <% and %>), the Razor version has only three (@)

I would say that the advantages of Razor are as follows:

  1. Concise syntax, which is very similar to the way you write regular C# code (check out the following recent blog post by Phil Haack comparing Asxp with Razor syntax: http://haacked.com/archive/2011/01/06/razor-syntax-quick-reference.aspx)
  2. Automatic HTML encoding of output (which helps protect you from html injection attacks)
  3. Built in (though not 100%) validation of your markup which helps you avoid unbalanced tags

The page-related concepts also map easily from what you have in ASPX

  • As you can see inline code is still allowed
  • Sections (which can be optional) are equivalent to content placeholders
  • Layout pages instead of Master pages
  • The concepts of full and partial views are the same
  • @functions { ... } blocks instead of <script runat="server"> ... </script>

In addition Razor has a number of useful concepts that I would say are better than what is available in ASPX:

  • @helper functions for really easy creation of functions that emit markup
  • @model keyword for specifying your view's model type without having to write a <%@ Page ... directive with the full class name

I would like to think that we have tackled a real problem, which is to allow you to more easily write concise and standards-compliant views while at the same time providing you with ways to refactor common code.

Of course, not everyone will prefer the syntax which is why we are also fully supporting the ASPX view engine. In addition you can check out Spark and NHaml, which are two 3rd-party view engines that enjoy significant community following. The following blog post has a good comparison of the different offerings: http://blogs.msdn.com/b/coding4fun/archive/2010/10/04/10070953.aspx

Tool to convert WebForm view engine markup to Razor view engine markup

15 votes

Does (or will) a tool exist to convert WebForm view engine markup (aspx) to Razor view engine markup (cshtml)?

I am not aware of any tool allowing to automatically do this because the Razor view engine is quite new and still in beta. There's not yet Visual Studio support like Intellisense and syntax highlighting.

Render partial view with dynamic model in Razor view engine and ASP.NET MVC 3

11 votes

When I try to render a partial view whose model type is specified as:

@model dynamic

by using the following code:

@{Html.RenderPartial("PartialView", Model.UserProfile);}

I get the following exception:

'System.Web.Mvc.HtmlHelper<dynamic>' has no applicable method named 'RenderPartial' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.

However, the same code in a .aspx file works flawlessly. Any thoughts?

Just found the answer, it appears that the view where I was placing the RenderPartial code had a dynamic model, and thus, MVC couldn't choose the correct method to use. Casting the model in the RenderPartial call to the correct type fixed the issue.

source: http://stackoverflow.com/questions/3822546

10 votes

Does any one have any idea about multiproject area support in asp.net mvc 3? As it was degraded to future status in mvc 2. If it is still not included then should we look forward for ASP.Net MVC Portable Areas via MvcContrib. Can you share your expreriences?

What are the recommended way for managing a large application? I read about MEF. In what scenarios MEF is recommended?

I'm the development lead on ASP.NET MVC at Microsoft.

There are no plans to include multi-project areas in ASP.NET MVC 3. However, it's definitely an area that we plan to revisit in the future.

In the meantime MvcContrib's solutions are probably the best bet. The MVC Futures download still includes an old (and perhaps only semi-functional) version of the original multi-project areas feature. Because the full source code for it is also available, you might be able to construct a solution that is customized to your needs.

ASP.NET MVC Beta Authorize attribute sends me to wrong action

9 votes

Today I started playing with the MVC 3 Beta. Started with an application from default MVC 3 template, added a new action in the Home controller as follows(with a view for it)

[Authorize]
public ActionResult Secured()
{
    ViewModel.Message = "This is secured area, only authenticated users should be here.";
    return View();
}

Now when I try to go to navigate to Secured action I get a 404 page not found error.

Here is the authentication section from my web.config.

<authentication mode="Forms">
  <forms loginUrl="~/Account/LogOn" timeout="2880" />
</authentication>

If I understood it right the Authorize attribute should result in a 401 unauthorized HTTP response which should be intercepted by the authentication handler and redirect me to the loginUrl. Which should result in Account/LogOn action.

My MVC 2 application works as expected and takes me to Account/LogOn action, am I missing something? or Is this a bug in MVC 3 beta?

ScottGu replies to a similar question on his blog that this is apparently a bug.

The workaround is to add this entry:

<add key="autoFormsAuthentication" value="false" />

to your <appSettings/> section in the web application's root web.config file.

ASP.NET MVC 3 Beta 1 Block Access to Razor views

9 votes

Is there a way to block access (404) to the Razor views in MVC 3 beta 1? When I create a brand new blank site (IIS7) and then access /views/home/index.cshtml from the browser, instead of the 404 I get this

    [InvalidCastException: Unable to cast object of type 'ASP.Index_cshtml' to type 'System.Web.IHttpHandler'.]
   System.Web.WebPages.WebPageHttpHandler.CreateFromVirtualPath(String virtualPath, VirtualPathFactoryManager virtualPathFactoryManager) +56
   System.Web.WebPages.WebPageRoute.DoPostResolveRequestCache(HttpContextBase context) +253
   System.Web.WebPages.WebPageHttpModule.OnApplicationPostResolveRequestCache(Object sender, EventArgs e) +89
   System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +148
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75

By default the web.config file in the views folder is set to block all file requests, but obviously this request is still getting through.

Steps to reproduce:
File -> New Project
ASP.NET MVC 3 Web Application
Internet Application (Razor)
F5
Navigate to /views/home/index.cshtml

I'm a dev lead on the ASP.NET team working on both ASP.NET MVC 3 and ASP.NET Web Pages and Razor.

This is not entirely fixed in ASP.NET MVC 3 RC, but it will be fully fixed in ASP.NET MVC 3 RTM.

There is nothing "terribly bad" that happens in ASP.NET MVC 3 RC or earlier: The worst that can happen is that someone can detect whether a view exists in your app - but they cannot get it to run (due to that weird exception). This is a slight security issue in that it is a form of information disclosure, but it is not a very severe issue.

In ASP.NET MVC 3 RTM all Razor views in ~/Views/... as well as any Razor views within an MVC Area are 100% blocked and will not be directly runnable by the browser. They will only be runnable as MVC view pages.

The new jQuery Templates from Microsoft and SEO

8 votes

Scott Guthrie just blogged about the new jQuery Templates that his team has been working on, and I must say... this looks really sweet. I have a multi-part question however, where the answer will influence my decision to use them.

I'm currently working on a project whereby the home page displays a list of upcoming events in your region. The event listing is much the same as that in http://nerddinner.com (but I'm not using any of their code).

I'm thinking about using the new jQuery Templates to format the information sent from my Controller (MVC). The current way I'm doing this is to send the ViewModel Object to the view (with all of the needed content), but to ALSO serialize the same ViewModel Object into JSON (passed using ViewData) that is used by the Bing Maps. Now I'm assuming that there's a performance hit in sending the same content twice, and therefore I think that sending JSON only and using it for both the Bing Maps and the content (using jQuery Templates) is a great idea.

In walks my question. Can search engines read the JSON in the page (and if so, will they use it for indexing), or are my pages going to be "blank" to the search engine because I'm displaying the content AFTER the page renders? The second part of this question is that, IF SEO will be affected, is there a better way of accomplishing what I need, or am I stuck sending the content twice? (remember, the map info and the content info will be exactly the same).

The templates are all JavaScript at the moment, something a crawler isn't going to execute. Google support AJAX enabled sites in a certain format...but no you won't see crawler support for this, at least not in the new future.

If anything, it'll hurt SEO...the price you pay for using newer technologies/formats the crawlers aren't designed to handle yet.

Warning: This answer has a shelf-life (hopefully) and should be invalid at some point (current date - Oct 05, 2010)...someone please edit me when this happens (and search engines handle this well).

Why is EF4 trying to re-create my database even though the model hasn't changed?

8 votes

I have an ASP.NET MVC 3 Beta website using SQL Server CE 4.0. With both ScottGu's NerdDinner example and my own code, I will sometimes get the following exception as soon as I try to access the database:

File already exists. Try using a different database name. 
[ File name = D:\Sourcecode\NerdDinner\NerdDinner\App_Data\NerdDinners.sdf ]

Line 17:         public ActionResult Index()
Line 18:         {
Line 19:             var dinners = from d in nerdDinners.Dinners
Line 20:                           where d.EventDate > DateTime.Now
Line 21:                           select d;

[SqlCeException (0x80004005): File already exists. Try using a different database name. [ File name = D:\Sourcecode\NerdDinner\NerdDinner\App_Data\NerdDinners.sdf ]]
   System.Data.SqlServerCe.SqlCeEngine.ProcessResults(IntPtr pError, Int32 hr) +92
   System.Data.SqlServerCe.SqlCeEngine.CreateDatabase() +1584
   System.Data.SqlServerCe.SqlCeProviderServices.DbCreateDatabase(DbConnection connection, Nullable`1 timeOut, StoreItemCollection storeItemCollection) +287
   System.Data.Objects.ObjectContext.CreateDatabase() +84
   System.Data.Entity.Internal.DatabaseOperations.Create(ObjectContext objectContext) +35
   System.Data.Entity.Infrastructure.Database.Create() +70
   System.Data.Entity.Infrastructure.CreateDatabaseOnlyIfNotExists`1.InitializeDatabase(TContext context) +360
   System.Data.Entity.Infrastructure.Database.Initialize() +272
   System.Data.Entity.Internal.InternalContext.Initialize() +90
   System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) +34
   System.Data.Entity.Internal.Linq.EfInternalQuery`1.Initialize() +140
   System.Data.Entity.Internal.Linq.EfInternalQuery`1.get_Provider() +29
   System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider() +34
   System.Linq.Queryable.Where(IQueryable`1 source, Expression`1 predicate) +63
   NerdDinner.Controllers.HomeController.Index() in D:\Sourcecode\NerdDinner\NerdDinner\Controllers\HomeController.cs:19

I cannot figure out why this works sometimes with an existing .dbf file and other times it complains. I have even tried explicitly setting the default behaviour with

Database.SetInitializer(new CreateDatabaseOnlyIfNotExists<...>());

Has anyone else experienced this?

  • Restarting Cassini doesn't seem to make a difference.
  • Hitting refresh in IE after receiving this error will make the exact same page load properly.

Install and use SQL Server CE CTP1, which is still downloadable on Microsoft sites. This solved my problem with that.

Why everybody hates ViewData?

8 votes

I wonder, why everybody hates ViewData so much?
I find it quite useful and convenient. I tell you why: typically every controller action has it's own ViewModel, so it's used only once and I find it very tedious to modify ViewData class every time I need to add extra portion of data to view (adding extra field to class usually leads to modifying its constructor). Instead I can write in controller

ViewData["label"] = someValue;
// in mvc 3 even better:
ViewData.Label = someValue

and in view

<%= ViewData["label"] %>
<%-- mvc 3: --%>
<%= ViewData.Label %>

or for complex types:

<% ComplexType t = (ComplexType)ViewData["label"]; %> // and use all benefits of strong typing 
<%= t.SomeProperty %>

Writing a controller action I do not have to switch to another class, when I need to add some data to view. And a big plus for me: no flooding your project with senseless classes and switching between them and others.
I agree that usage of "magic strings" could lead errors which are not caught by compiler, but these errors localized in very small part of code and can be discovered very quickly. Besides, how do you think guys working with dynamic languages (rails, django) lives without strong typing at all?)

What's your opinion about using ViewData?

I think this goes beyond just the magic string argument. I would argue that ViewModels are a good thing and not senseless classes because they help keep the Views cleaner and easier to read than accessing ViewData all over the Views.

When you get to five, ten, twenty pieces of data that need to be displayed in a view are you really going to pass all that data over as ViewData? It will make your view harder to follow and that data won't have any meaning. Making a ViewModel and strongly typing the view to that ViewModel will not only make the code easier to read, but you don't have to go casting ViewData objects all over your code.

I do think ViewData is good for certain cases, but when you are dealing with a lot of data it can easily be abused in my opinion.

What does Html.HiddenFor do?

7 votes

Although I have read the documentation on Html.HiddenFor, I've not grasped what is it used for...

Could somebody explain its uses and give a short example?

Where should those helpers go in the code?

Creates a hidden input on the form for the field (from your model) that you pass it.

It is useful for fields in your Model/ViewModel that you need to persist on the page and have passed back when another call is made but shouldn't be modified seen by the user.

Consider the following ViewModel class:

public class ViewModel
{
    public string Value { get; set; }
    public int Id { get; set; }
}

Now you want the edit page to store the ID but have it not be editable seen:

<% using(Html.BeginForm() { %>
    <%= Html.HiddenFor(model.Id) %><br />
    <%= Html.TextBoxFor(model.Value) %>
<% } %>

Which results in the equivalent of the following HTML:

<form name="form1">
    <input type="hidden" name="Id">2</input>
    <input type="text" name="Value" value="Some Text" />
</form>

Pattern for retrieving complex object graphs with Repository Pattern with Entity Framework

6 votes

We have an ASP.NET MVC site that uses Entity Framework abstractions with Repository and UnitOfWork patterns. What I'm wondering is how others have implemented navigation of complex object graphs with these patterns. Let me give an example from one of our controllers:

var model = new EligibilityViewModel
   {
       Country = person.Pathway.Country.Name,
       Pathway = person.Pathway.Name,
       Answers = person.Answers.ToList(),
       ScoreResult = new ScoreResult(person.Score.Value),
       DpaText = person.Pathway.Country.Legal.DPA.Description,
       DpaQuestions = person.Pathway.Country.Legal.DPA.Questions,
       Terms = person.Pathway.Country.Legal.Terms,
       HowHearAboutUsOptions = person.Pathway.Referrers
   };

It's a registration process and pretty much everything hangs off the POCO class Person. In this case we're caching the person through the registration process. I've now started implementing the latter part of the registration process which requires access to data deeper in the object graph. Specifically DPA data which hangs off Legal inside Country.

The code above is just mapping out the model information into a simpler format for the ViewModel. My question is do you consider this fairly deep navigation of the graph good practice or would you abstract out the retrieval of the objects further down the graph into repositories?

In my opinion, the important question here is - have you disabled LazyLoading?

If you haven't done anything, then it's on by default.

So when you do Person.Pathway.Country, you will be invoking another call to the database server (unless you're doing eager loading, which i'll speak about in a moment). Given you're using the Repository pattern - this is a big no-no. Controllers should not cause direct calls to the database server.

Once a C ontroller has received the information from the M odel, it should be ready to do projection (if necessary), and pass onto the V iew, not go back to the M odel.

This is why in our implementation (we also use repository, ef4, and unit of work), we disable Lazy Loading, and allow the pass through of the navigational properties via our service layer (a series of "Include" statements, made sweeter by enumerations and extension methods).

We then eager-load these properties as the Controllers require them. But the important thing is, the Controller must explicitly request them.

Which basically tells the UI - "Hey, you're only getting the core information about this entity. If you want anything else, ask for it".

We also have a Service Layer mediating between the controllers and the repository (our repositories return IQueryable<T>). This allows the repository to get out of the business of handling complex associations. The eager loading is done at the service layer (as well as things like paging).

The benefit of the service layer is simple - more loose coupling. The Repository handles only Add, Remove, Find (which returns IQueryable), Unit of Work handles "newing" of DC's, and Commiting of changes, Service layer handles materialization of entities into concrete collections.

It's a nice, 1-1 stack-like approach:

personService.FindSingle(1, "Addresses") // Controller calls service
 |
 --- Person FindSingle(int id, string[] includes) // Service Interface
      |
       --- return personRepository.Find().WithIncludes(includes).WithId(id); // Service calls Repository, adds on "filter" extension methods
           |
            --- IQueryable<T> Find() // Repository
                |
                 -- return db.Persons; // return's IQueryable of Persons (deferred exec)

We haven't got up to the MVC layer yet (we're doing TDD), but a service layer could be another place you could hydrate the core entities into ViewModels. And again - it would be up to the controller to decide how much information it wishes.

Again, it's all about loose coupling. Your controllers should be as simplistic as possible, and not have to worry about complex associations.

In terms of how many Repositories, this is a highly debated topic. Some like to have one per entity (overkill if you ask me), some like to group based on functionality (makes sense in terms of functionality, easier to work with), however we have one per aggregate root.

I can only guess on your Model that "Person" should be the only aggregate root i can see.

Therefore, it doesn't make much sense having another repository to handle "Pathways", when a pathway is always associated with a particular "Person". The Person repository should handle this.

Again - maybe if you screencapped your EDMX, we could give you more tips.

This answer might be extending out a little too far based on the scope of the question, but thought i'd give an in-depth answer, as we are dealing with this exact scenario right now.

HTH.

ASP.NET MVC - HttpException or return view?

6 votes

I'm trying to make a request for a customer and if the customer doesn't exist it should return some kind of "Not found" page. Which of the below would be the best practice to use for such a task, and why?

public ActionResult Index(int id)
{
    if (customerService.GetCustomerById(id) == null)
        return View("NotFound");

    return View();
}

or

public ActionResult Index(int id)
{
    if (customerService.GetCustomerById(id) == null)
        throw new HttpException(404, "Customer not found");

    return View();
}

This is a good question (+1) as there are some differing opinions out there about when to use HTTP exception codes and when not.

REST disciples will likely tell you to go the HTTP Exception route because they believe that a URI identifies a conceptual resource (i.e.: the actual object/thing to which you are referring - a Customer in this case), and if that resource doesn't exist then you should get a 404 error back.

However, some will disagree and say that you should only pass back a 404 error if the physical resource, e.g. a file, doesn't exist.

I tend to fall into the second camp and would recommend that you return 200 OK with a custom view stating that the customer specified by the ID could not be found.

R# "cannot resolve view" when changing the default location for views + custom ViewEngine for ASP.net MVC2

6 votes

We have a project in ASP.net MVC2 were we have our own ViewEngine that overrides were views locations are. Problem is that Resharper 5.1 is not picking up this, of course. Is there anyone who knows of a way to extend R# to pick this up?

I don't want to disable R# to not try to resolve view globally or local with the R# comment. I want to full tooling support.

R# and Visual Studio don't have support for custom view locations. Imagine views stored in a database for example. You could still write to the R# team and ask to implement this feature in the next version.

Asp.Net MVC and Web Services

5 votes

I have an existing Asp.Net MVC Website and I would also like to provide a Web Service from the same domain.

What is the best way to approach creating a web service in this scenerio?

Do I add to this project or...?

You should be able to add an WebService file directly to the MVC project. Right click on solution and select add new item, then select the web category and att the bottom of the list there should be Web Service.

Just remember to check that the routes does not eat up the call to the webservice.

That way the webservice can get access to the same model classes as the MVC application.

Should I expose web methods via ASP.NET MVC actions or WCF?

5 votes

I want to be able to Ajax-ly retrieve JSON data from some kind of web service. (The web service calls will be wrapping a call to SQL, processing the DataSet returned, and returning a JSON representation.) Initially, I thought an ASP.NET MVC project with appropriately named Controllers and Actions that return JsonResults would suffice. However, a colleague suggested WCF might be a better fit for something like this. It's been my experience that WCF is difficult to configure; moreover, the way MVC exposes Actions through Controllers seems very elegant.

Which is a better fit for what I'm trying to do, MVC or WCF?

If you're going to create services that create strictly JSON (with no other end-points on the horizon), I find that .NET MVC is much easier to use and produces better results.

If you think you might want multiple types of end-points (SOAP, etc.) at some point in the future, then go with WCF.

Keep in mind that there are rumblings from the WCF team that they are about to release something that will completely overhaul how RESTful JSON services in WCF are done. It should be interesting.

ASP.NET MVC/C#: Can I avoid repeating myself in a one-line C# conditional statement?

5 votes

Consider the following code that I'm using when displaying a Customer's mailing address inside a table in a view:

<%: Customer.MailingAddress == null ? "" : Customer.MailingAddress.City %>

I find myself using a fair amount of these ternary conditional statements and I am wondering if there is a way to refer back to the object being evaluated in the condition so that I can use it in the expression. Something like this, perhaps:

<%: Customer.MailingAddress == null ? "" : {0}.City %>

Does something like this exist? I know I can create a variable to hold the value but it would be nice to keep everything inside one tight little statement in the view pages.

Thanks!

No, there is not a way to do precisely what you're asking without creating a variable or duplicating yourself, though you can do something like this:

(Customer.MailingAddress ?? new MailingAddress()).City ?? string.Empty

This presumes that a new MailingAddress will have it's city property / field null by default.

The last null coalescence can be removed if creating a new MailingAddress initializes the city field / property to empty string.

But this isn't actually shorter, and it's more hackish (in my opinion), and almost certainly less performant.