Best asp.net-mvc-3 questions in July 2011

Adding custom ValueProviderFactories to ASP.NET MVC3?

8 votes

I was looking to try and add a Protobuf ValueProviderFactory to MVC3 so that I could pick out the MIME type and deserialize the raw data into objects for action parameters. I could also use this to change the default Json serializer.

Looking at JsonValueProviderFactory.cs this shouldn't be too difficult, but the factories all appear to be hard-coded.

For Protobuf I may be able to do something with an IValueProvider but I haven't even checked yet what MVC3 does when it recieves an MIME type of application/x-protobuf.

Am I going about this the right way?

UPDATE

I found this blog post that talks about creating an IValueProvider. It then mentions at the bottom that this changed around MCV2. He changed it to a ValueProviderFactory and calls :

ValueProviderFactories.Factories.Add(new HttpCookieValueProviderFactory());

But in MVC3 this property is read only.

It turns out that it is not read only and you can add providers as follows:

ValueProviderFactories.Factories.Add(new MyValueProviderFactory());

I would have know this had I checked myself!

I've done some more searching today, and this blog post seems to suggest that the DependencyResolver will find any classes that inherit ValueProviderFactory. I'm using MEF for dependency resolution so I can just add an Export attribute and it'll get picked up automatically.

I now have a further issue writing a custom ValueProviderFactory for protobuf-net.

View Model Patterns and usage in ASP.NET MVC3 (Also, using EF 4.1)

5 votes

I have been searching for an answer to this question for days and it is driving me insane. Currently I am working on a project using ASP.NET MVC 3 and am trying to utilize a ViewModel per controller approach as has been suggested by so many articles and tutorials I have checked out. To better illistrate what I am asking I will outline below:

Lets say I have a pretty simple and straight forward model. Users, Customers, Addresses, Phone Numbers, Orders, Products, Categories, etc... When a user registers for a new account on my site I would like to: 1) create an account for them (this is just an account id, customer type) 2) Add their customer demographic data to Customers 3) Add N-addresses and address types 4) Add N-phone numbers with type as well.

As far as I have got is deciding that I need a RegisterCustomerForRegistrationControllerViewModel. My predicament is what does this model look like? I am trying to be as DRY as possible yet when implementing this pattern I seem to repeat myself at each turn. At what level do I put DataAnnotations for validation? So do I simply new up a new Customer() even if I only want to use one property from the class in a given ViewModel?

I'm not even confident at this point that this is a correct assumption. There seems to be so much opinion on the topic yet so few concrete examples of implementation. I am hoping someone can point me in the right direction and maybe present some code snippets along the way... I hope this is all clear enough and if not please feel free to ask follow up questions.

Again, Thanks in advance!

Repeating simple properties across two distinct layers of an application is not a violation of DRY. Its just good design.

DataAnnotations go on ViewModels.

ViewModel will look something like

public class RegisterCustomerViewModel
{
    [Required]
    public string Name { get; set; }
    public List<AddressViewModels> Addresses { get; set; }
    public List<PhoneNumberViewModel> PhoneNumbers { get; set; |

} 

How to create a editor template for DateTime with 3 fields?

5 votes

I want to create an editor template for DateTime, I need 3 separated fields:

(DropDown) Day    |    (DropDown) Month    |    (DropDown) Year

How and where do I create this file? And what do I need to do to turn these 3 fields into a single DateTime when I post to a controller?

In your Views/Shared/EditorTemplates folder create a partial view called DateTime.ascx.

The code for this EditorTemplate should be something like

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<DateTime?>" %>

<%
    string controlId = ViewData.TemplateInfo.HtmlFieldPrefix.Replace('.', '_');
%>

<script type="text/javascript">
$(function () {
    $('#<%: controlId %>_Day, #<%: controlId %>_Month, #<%: controlId %>_Year').live('change', function () { updateHiddenDate('<%: controlId %>'); });
    $('#<%: controlId %>_Day').val('<%: Model.HasValue ? Model.Value.Day.ToString() : "" %>');
    $('#<%: controlId %>_Month').val('<%: Model.HasValue ? Model.Value.Month.ToString() : "" %>');
    $('#<%: controlId %>_Year').val('<%: Model.HasValue ? Model.Value.Year.ToString() : "" %>');
    updateHiddenDate('<%: controlId %>');
});

function updateHiddenDate(hiddenDateId) {
    $('#' + hiddenDateId).val($('#' + hiddenDateId + '_Year').val() + "-" + $('#' + hiddenDateId + '_Month').val() + "-" + $('#' + hiddenDateId + '_Day').val());
}
</script>

<select id="<%: controlId %>_Day">
<%  for (int dayOrdinal = 1; dayOrdinal <= 31; dayOrdinal++)
    {
        Response.Write(string.Format("<option value=\"{0}\">{0}</option>", dayOrdinal));
    }
%>
</select>
<select id="<%: controlId %>_Month">
<%  for (int monthOrdinal = 1; monthOrdinal <= 12; monthOrdinal++)
    {
        Response.Write(string.Format("<option value=\"{0}\">{1}</option>", monthOrdinal, System.Globalization.DateTimeFormatInfo.CurrentInfo.MonthNames[monthOrdinal - 1]));
    }
%>
</select>
<select id="<%: controlId %>_Year">
<%  for (int yearOrdinal = DateTime.Now.Year - 5; yearOrdinal <= DateTime.Now.Year + 5; yearOrdinal++)
    {
        Response.Write(string.Format("<option value=\"{0}\">{0}</option>", yearOrdinal));
    }
%>
</select>

<%: Html.Hidden("", Model.HasValue ? String.Format("{0:yyyy-MM-dd}", Model) : "") %>

That creates an editor template with a hidden field containing an ISO 8601 representation of the date which the MVC ModelBinder can parse.

The jQuery updates the hidden field whenever the dropdowns change. Note the use of the ViewData.TemplateInfo.HtmlFieldPrefix that I use to get the generated id of the hidden field.

Note that this solution drops in easily without faffing about with Custom ModelBinders because we construct a single form value containing the full datetime. However, this does mean that

  1. You rely on the client having javascript enabled, and
  2. You need to include a script reference to the jQuery library in your masterpage (e.g. <script type="text/javascript" src="../../Scripts/jquery-1.4.1.min.js"></script>)

If that's not acceptable, you will have to look at Custom ModelBinders as @Jon has pointed to.

Conditional compilation turned off warning when mixing razor and javascript

5 votes

The following snippet triggers a "Conditional compilation turned off" warning in one of my views. Do you have an idea on how to fix it?

<script type="text/javascript">
    $(document).ready(function () {
        @RenderSection("JQueryDocumentReady",false)
    });
</script>

I tried to insert a semicolon at the end of the render section statement but it didn't help.

Thank you.

NOTE: Answer accepted because of alternative suggestion to the question, not solution given for the problem in title.

I'm not 100% sure what Conditional Compilation has to do with being in a <script> block, but I did find that wrapping the statements in parenthesis fixed the problem.

@(RenderSection("JQueryDocumentReady"))

I do think this method has a bit of code small though. It's not a problem to just have a script section and assign things to document ready on each page. It really isn't going to save you much work, and it will force you to put javascript on views outside of script tags the way you have chosen to do it.

MVC 3 and "Javascript-Disabled" browsers.

4 votes

I have a requirement to implement a web application using MVC 3, which works on browsers even if javascript is disabled. There are a lot of concepts in MVC 3 which rely on the use of jquery.

  1. What are the concepts which won't work in the case of "javascript-disabled" browsers?
  2. For those concepts which won't work, are there any alternative ways to implement those concepts in MVC 3?
  3. With these requirements, is it a good idea to implement such a website using MVC 3, or should it be implemented in asp.net (with every thing done on server side)?

MVC 3 does NOT depend on jQuery to function properly

The beauty of MVC 3 is that it is pre-packaged with a jQuery plugin which provides unobtrusive form validation. Unobtrusive means that it will work even if Javascript is disabled. MVC 3 does NOT require jQuery nor Javascript to work as intended.

Take a moment to read this blog post. The author does a good job explaining how MVC 3 and jQuery work together.

http://www.matthidinger.com/archive/2011/02/22/Progressive-enhancement-tutorial-with-ASP-NET-MVC-3-and-jQuery.aspx

Quick and Dirty Explanation of MVC3 Ajax/JS files, please :)

4 votes

I've been trying to find a decent article or snippet that explains what the difference is in JS (Validate & Ajax) files are Microsoft includes with MVC3 and I've not been able to find anything.

Would someone kindly explain the differences and how they're supposed to be use (e.g. does one piggy-back off the other, used instead for X reason, etc):

  • jquery.validate, jquery.validate.unobtrusive and MicrosoftMVCValidation
  • jquery.unobtrusive-ajax, MicrosoftAjax & MicrosoftMVCAjax

To add on to this - basically why would I use jquery.validate vs. the unobtrusive or MVC validation. Or what is their purpose in conjunction with jquery.validate, etc. Likewise for the Ajax files.

Thanks a ton in advance :)

Here are my 2 cents:

  • (jquery.validate and jquery.validate.unobtrusive) vs (MicrosoftMVCValidation)

Pick the first as it is unobtrusive meaning that HTML5 data-* attributes are generated on the input fields and validators are unobtrusively attached into separate javascript files. With Microsoft validation your final markup is no longer markup but it is markup mixed with javascript. Not only that this increases the size of your HTML pages but it makes them uglier and impossible to benefit from the browser caching capabilities of external static resources.

Depending on the project I decide whether I would use directly jQuery.validate plugin or benefit from the autogenerated HTML5 data-* attributes and let the jquery.validate.unobtrusive script do the automatic client script validation based on some DataAnnotations rules on my view models. Well, actually I don't use DataAnnotations but FluentValidation.NET but it doesn't matter to the client side as they both emit ModelMetaData. I must agree that with ASP.NET MVC 3 Microsoft made a step forward with those jquery.validate.unobtrusive scripts. But basically it will really depend on the project I am working on and the amount of control I need.

  • (jquery.unobtrusive-ajax) vs (MicrosoftAjax & MicrosoftMVCAjax)

None of the above :-) I would recommend you using pure jQuery but if you had to pick between the jquery.unobtrusive-ajax and MicrosoftAjax pick the first for the exact same reasons as the previous one. Now I should probably explain why I don't like either. I have already pointed out the complete crapiness of all Microsoft* scripts so let's not repeat it again. Even Microsoft themselves realized their mistake and starting from ASP.NET MVC 3 jQuery becomes the default library and their scripts are only included for compatibility with older applications that you might be converting, but I guess in future versions they will disappear completely. The question is why pure jQuery compared to jQuery.unobtrusive-ajax? Well, with the first I have far more control over the events of the AJAX requests. With jquery.unobtrusive-ajax for example when JSON objects are returned in the OnSuccess callback they are not automatically parsed into javascript objects you will have to do the parsing manually and that is just driving me nuts.

How to pass parameters to a partial view in ASP.NET MVC?

2 votes

Suppose that I have this partial view:

Your name is <strong>@firstName @lastName</strong>

which is accessible through a child only action like:

[ChildActionOnly]
public ActionResult FullName(string firstName, string lastName)
{

}

And I want to use this partial view inside another view with:

@Html.RenderPartial("FullName")

In other words, I want to be able to pass firstName ans lastName from view to partial view. How should I do that?

use this overload (docs):

public static void RenderPartial( this HtmlHelper htmlHelper, string partialViewName, Object model )

so:

@{Html.RenderPartial("FullName", new { firstName = model.FirstName, lastName = model.LastName});}

AjaxOptions OnSuccess callback with parameter not working

1 votes

I am trying to use AjaxOptions.OnSuccess to call a javascript function and pass a parameter to it. I am able to call a basic function with no parameters without a problem, it's just the parameter passing.

Here is my JS function:

<script type="text/javascript">
    function removeRow (itemId) {

        alert(itemId);
    }
</script>

And my AjaxOptions declaration in razor:

New AjaxOptions With {.OnSuccess = "function(){removeRow(" + item.Id.ToString + ");}"}

On the client side the link appears like this:

<a data-ajax="true" data-ajax-success="function(){removeRow(3);}" href=...

Any idea what I'm doing wrong?

Thanks!

Try this:

New AjaxOptions With {.OnSuccess = String.Format("removeRow({0})", item.Id) }

MVC3 Controller folder won't appear in URL

0 votes

This is just an example which I can't figure out how to get it work.

In my MVC3 Controller folder, if I add a new folder called "Admin" and add a controller "News" with an action "Index", you get a server error when you try to open that url (404):

http://url/Admin/News

Even when you type "/Index" behind it, it won't work. How can you make a hierarchy which will result in similar URL's? Just to be clear, I want to create URL's like:

http://url/folder1/folder2/controller/action

Thanks

You seem to be thinking in the mindset of "physical file paths" still. .NET MVC uses the concept of routing where you define routes that map to controller classes and actions. In plain words, you're not mapping to a file, you're mapping to a class.

If you look in the global.asax file of your web project you will see a method named RegisterRoutes(). This method wires up all of the available routes for your site that will be utilized to find the correct controller/action/param/pattern to execute.

Now, the way I'd recommend solving what you're looking for would be by creating an area. It sounds like you want to have an administrative section to your website so I'd do the following:

Right click on your website project, select "Add", select "Area"

enter image description here

Give your area a name, in this case "Admin" would make sense

You solution explorer will now have added the "area" Admin. Notice how it mimics the structure and layout of the standard project, only in it's own folder.

enter image description here

Add a controller in the newly created administrative area and name it "News" Add your actions

Here's a test result URL doing this:

enter image description here

This solution is for simplicity's sake. If you want to take if further you will have to delve into creating your own routes in the RegisterRoutes() method I spoke of above. Routing is something you should gain a solid grasp of so I recommend doing so.