Posts Tagged 'ASP.NET MVC'

Using Web Forms in an MVC Site

I’m teaching an HTML5 course this week, but one of my students had an ASP.NET question: how do you combine Web Form pages with ASP.NET MVC? It’s an interesting question, and not one that’s covered in any of our courses. Our MVC class covers MVC, our Web Form course covers Web Forms… and never the twain shall meet. But actually, combining the two is very straightforward, and can be very useful. ASP.NET MVC is great… but it doesn’t do grids anywhere near as easily or as well as Web Forms. And what if you have legacy Web Form pages that you want to include in your shiny new MVC site so that you don’t have to recreate absolutely everything on day one?

Here’s how you do it.

First, let’s build an MVC site. I created a standard MVC 4 site:

Using the Internet Application template and Razor syntax:

That gives a basic structure and sample controllers/views:

Now I want to add a nice grid to display a list of restaurants. I could do this the hard way with MVC, but why bother when I could use the Web Forms GridView?

So first I create a quick Entity Framework .edmx file for the table I want to display:

Then I add a Web Form to my site. That’s easy. Just right-click on the project and use Add | New Item….

Then I drag on a GridView…

And configure it to use an Entity Data Source pointed at the Restaurants entities, with some auto format goodness to make it purdy…

Then I add a link inside the layout view that points at my .aspx page (so NOT an MVC style route):

And when I click on it – tara! – I have a working Web Form page with a Grid inside an MVC application:

There is, of course, a catch. You can get some issues mixing the two forms of routing together (MVC logical routes and Web Form end points). The solution here is to tell MVC to ignore incoming routes that contain .aspx. You do this inside the RouteConfig in the App_Start folder:

And now we have an application that uses both ASP.NET technologies.

Of course, in the real world you’d have to worry about making your Web Forms look and feel like your MVC site, and there’s the whole thorny issue of keeping them in sync and how you can have a well-organized site with two different approaches to the UI…. But on the other hand, it’s nice to be able to take advantage of Web Forms where they can do things easily, and it makes migration from Web Forms to MVC much easier.

Kevin Rattan

For other related information, check out these courses from Learning Tree:

Building ASP.NET Web Applications: Hands-On

Building Web Applications with ASP.NET MVC

Supporting Multiple Versions of jQuery

I was in New York recently teaching my ASP.NET Web Forms class while one of my colleagues was teaching my jQuery class a couple of doors away. One of the students in the jQuery class asked an interesting question, and since another instructor – Randy Casburn – was sitting in the back of the room, he had some fun playing around with alternative answers. I thought the code he came up with might be useful to someone, so I’m posting it here – along with two other answers to the question: ranging from the officially recommended (but restrictive) to the deeply unofficial (but clever and very flexible).

Why might you want to do have multiple versions? There are all sorts of reasons:

  • You may be using a plugin that relies on an older version
  • As a developer, you may not have control over the whole page – just your portion of it – and other developers/teams may be adding their versions of jQuery elsewhere on the page. (This is particularly true if you have a complex server side set up, and your pages are built from different elements maintained by different developers/teams).
  • You may use a third party tool that relies on a particular version
  • A component may inject an older version of jQuery whether you want it to or not.

So – first, what are the official answers to the question?

Answer one: don’t do it, use the migration plugin.

The idea here is that you don’t run an older version of jQuery as well as a newer version, you use the migrate plugin to add backwards compatibility to your newer version (1.9+). First replace your old version of jQuery with the new one, then add a reference to the migrate plugin. As if by magic, the deprecated elements removed in the more recent version are restored and your existing code works:

<script src=”http://code.jquery.com/jquery-1.10.2.js”></script&gt;

<script src=”http://code.jquery.com/jquery-migrate-1.2.1.js”></script&gt;

Advantages: you only have one version of jQuery, and the plugin provides a migration path until you get around to updating.

Disadvantages: it only goes back as far as jQuery 1.6.4, so if you need to support an older version, it doesn’t help.

Answer two: use .noConflict()

The noConflict() method is designed to relinquish jQuery’s use of the $ alias so that jQuery can work alongside other JavaScript libraries. It works just as well when that ‘other’ library is an older version of jQuery, even if the jQuery team does not recommend having more than one version.

The following code….

<script
src=’http://code.jquery.com/jquery-1.6.min.js’></script>

<script
src=’http://code.jquery.com/jquery-1.7.2.min.js’></script>

<script>

    jQuery.noConflict();

/**

    Newer version code would be here

    Note: use of ‘on()’ method

**/

    jQuery(function(){

        jQuery(‘#new’).on(‘click’, function(e){

            e.preventDefault();

            jQuery(‘body’).append(‘You clicked on the “jQuery” link. It used version: ‘+jQuery.fn.jquery+‘<br/><br/>’);

        });

    });

/**

    Legacy code would be here

    Note: use of ‘bind()’ method

**/

    $(function(){

        $(‘#old’).bind(‘click’, function(e){

            e.preventDefault();

            $(‘body’).append(‘You clicked on the “$” link. It used version: ‘+$.fn.jquery+‘<br/><br/>’);

        });

    });


</script>

</head>

<body>

<a
id=’old’
href=’#’>Execute older version (jQuery as $)</a>

<br/><br/>

<a
id=’new’
href=’#’>Execute newer version (jQuery as jQuery)</a>

<br/>

</body>

Leads to the following output when both buttons have been clicked:

That’s nice if you need to support two versions of jQuery, one of which is older than 1.6.4. But what if you have a situation where you absolutely have to use more than two versions of jQuery side by side? Here is Randy’s solution:

Answer three: Alias, alias, alias

The solution here is to add the version of jQuery you want to use and assign it to a variable. Then add another version, and assign it to another variable. Repeat as necessary.

Here’s the code:

    <script
src=’http://code.jquery.com/jquery-1.3.pack.js’></script>

    <script>

    var $$$ = jQuery;

    </script>

    <script
src=’http://code.jquery.com/jquery-2.0.3.min.js’></script>

    <script>

    var $$ = jQuery;

    </script>

    <script
src=’http://code.jquery.com/jquery-1.6.min.js’></script>

    <script
src=’http://code.jquery.com/jquery-1.7.2.min.js’></script>


<script>

    jQuery.noConflict();

    $$$(function(){

        $$$(‘body’).append(‘/————-/<br>$$$ is version: ‘+$$$.fn.jquery);

        $$$(‘body’).append(‘<p>’ + testOnSupport($$$) + ‘</p>’);

    });

    $$(function(){

        $$(‘body’).append(‘/————-/<br>$$ is version: ‘+$$.fn.jquery);

        $$(‘body’).append(‘<p>’ + testOnSupport($$) + ‘</p>’);

    });


    jQuery(function(){

        jQuery(‘body’).append(‘/————-/<br>jQuery is version: ‘+jQuery.fn.jquery);

        jQuery(‘body’).append(‘<p>’ + testOnSupport(jQuery) + ‘</p>’);

    });

    $(function(){

        $(‘body’).append(‘/————-/<br>$ is version: ‘+$.fn.jquery);

        $(‘body’).append(‘<p>’ + testOnSupport($) + ‘</p>’);

        $(‘body’).append(‘/————-/<br>’);

    });

    function testOnSupport(x)

    {

     if (typeof (x(‘body’).on) == ‘undefined’) nope = ‘Does not support on()’; else nope = ‘Does support on()’;

     return nope;

    }


</script>

</head>

<body>

<br>

</body>

And here’s what the output looks like:

Do I recommend having multiple versions of jQuery side by side? Emphatically not. But if you have no choice in the matter, there are a surprising number of ways to get there. Whichever you use, do be careful of the order in which you add your references – if you’re using .noConflict() for example, you need to make sure you put your script files and the .noConflict() code AFTER any older version of jQuery injected by a component.

Kevin Rattan

For other related information, check out this course from Learning Tree:

jQuery: A Comprehensive Hands-On Introduction

Allowing Users to Select Mobile or Desktop Views

My jQuery Mobile/ASP.NET MVC site, cocktailsrus.com, began as a pure jQuery Mobile site. I then added a desktop view and automatically switched users to the appropriate view depending on their device. This works pretty well – especially with the 51Degrees NuGet to improve on the built-in device detection – but even so, there are occasions when the automated detection fails. Someone with a new device comes to the site, the device isn’t recognized, and the user ends up with the wrong version.

This bugs me.

Or, to be more accurate – what bugs me is that there’s no way for the user to change to the appropriate view.

That’s is the problem with automatic device detection: it’s fine until it doesn’t work. Then you’re stuck. So the answer, obviously, is to provide the user with a means to override the default device detection. They need a button that lets them switch to the other view.

The problem is – how to override the detection and automatic version selection, especially since I am relying on a 3rd party tool to do the detection for me? Fortunately, there is a solution in the form of another NuGet: jQuery Mobile MVC. Scott Hanselman blogs about it here. It’s an excellent solution to the problem… but the sample view user control provided in the NuGet needs a little tweaking if it’s going to solve the specific problem I outlined above.

First, let’s take a look at the NuGet and what it does for us. So let’s install it:

If you don’t already have a mobile specific .layout file, then the install gives you a basic version with associated CSS etc. designed for mobile devices:

And right at the top of the mobile view is the output (“Displaying mobile view Desktop View”) from a view user control, _ViewSwitcher. This control is really what the NuGet is all about.

Clicking on the link leads the user off to a small controller, ViewSwitcherController, with the single method SwitchView:

So… if you are in a mobile device, you get a choice between the mobile and the desktop view. When you click on the link, it sets the BrowserOverride and the user is given the view of their choice rather than the default. Nice.

It’s very neatly done… except that it doesn’t actually solve the problem I started out with. My problem was – what to do about a mobile device that wasn’t picked up as a mobile device… and this code wouldn’t solve that problem.   It will only display the choice of view to devices that the system already thinks are mobile devices. A mobile device that isn’t detected won’t get any option to switch to a mobile view – even if the _ViewSwitcher control is added to the desktop version. The problem is in the first if statement:

Only recognized mobile devices get the links. I want a user with an unrecognized mobile device to be able to select the mobile view. So in my version, I remove the outer if statement and also some of the ancillary text so that I can use the links as part of the menus. Also, because both versions of the site make extensive use of Ajax, I explicitly redirect the user to the home page when they switch view (otherwise, they might end up getting a partial page):

With this small tweak, I now have links in both the mobile and the desktop versions that seamlessly allow the user to override the default selection and switch between the different views:

Now I just need to do something about that bottom menu, as it’s getting too bulky. Time to upgrade to jQuery Mobile 3 and put the navigation in a panel. Onwards….

Kevin Rattan

For other related information, check out this course from Learning Tree:

Building Web Applications with ASP.NET MVC

Internationalizing ASP.NET MVC Applications

A couple of weeks ago I posted about internationalization with ASP.NET Web Forms. In this post, I’m going to look at how ASP.NET MVC handles internationalization. The good news is that you can localize in a broadly similar way and it’s still nice and easy. The bad news is that MVC does less for you and makes you jump through a few hoops to get it working.

What’s the same?

Resource files, for one thing.

What’s different?

You don’t use App_LocalResources, and Visual Studio doesn’t generate the keys in the resource file for you.

Let’s create the same basic page that we did with Web Forms – a contact form for sending an email. Here is the controller method, passing an Email model through to a strongly typed view Contact.cshtml:

And here is part of the View generated by Visual Studio 2012:

We want the labels to display appropriate text depending on the user’s language settings. In Web Forms, we can get the tools to generate a resource file with keys for relevant text. Here, we have to do it ourselves – and the resource files live with the views. I right-clicked on the Home folder and selected Add | Resources Files…

I called the first file Contact.resx. (The lack of a language specifier makes it the default). Then I went through and added the keys and values I wanted in English. Next, I copied it to create Contact.fr.resx and amended the values to my best guess at the French words I needed. (If someone speaks three languages, they are multi-lingual. If they speak two, they are bi-lingual. If they speak one… they are English. I am very English).

Here is the default file:

Here is the French version:

And here is the structure in Solution Explorer. Notice that the files are in the same folder as the views, NOT in App_LocalResources.

The next step is to tell our View to use the resources. I set the Custom Tool Namespace to Resources.Local to keep it nice and simple:

Then I used the second argument on LabelFor to specify the text, and passed in the relevant key from the resource file:

So everything should work now, right? We’ve created the resource files, pointed the views at them and it should all just work… Let’s run it and see:

Oops. It turns out the default protection level on the file is internal, which doesn’t work. You can use the dropdown at the top of the resource file to change it to public:

And here’s what you get in the Properties window – PublicRexXFileCodeGenerator rather than the default ResXFileCodeGenerator:

Now when we run it with English settings we get:

And when we pretend to be French, we get:

So, overall, it’s very similar to Web Forms, but just different enough to require a little extra work. You can also take an alternative approach and create separate views for each language. For me that’s a step too far, especially as I am likely to have mobile and standard views, and given that you can have device specific views as well, the complication soon increases exponentially. [Back in the 1990s, I worked on a project with 9 different versions of every page (IE, Netscape, Accessible IE, Accessible Netscape, Welsh IE, Welsh Netscape, Accessible Welsh… I can’t go on; the memory is just too painful) and I avoid view proliferation at all costs.]

There is, of course, more to internationalization than resource files. There’s programmatic control – letting your end user choose their language – and localizing strings that come from model classes, such as data annotation validation messages. So I may well return to internationalization again in a future blog post…

Kevin Rattan

For other related information, check out this course from Learning Tree:

Building Web Applications with ASP.NET MVC

Building ASP.NET Web Applications: Hands-On

Editing Collections in ASP.NET MVC

A recent comment on one of my earlier articles got me thinking again about ASP.NET MVC model binding and validation. The comment was from Bart Calixto, and was to the effect that my concern over MVC validation and repeating forms was misplaced – that simply binding to a collection meant that MVC could handle this itself.

My immediate response was that the problem remains – that by default MVC does not generate unique IDs for repeating forms and creates malformed HTML (and causes issues with client-side validation). However – Bart is right that it is possible to get MVC to manage the client-side IDs properly by binding to a collection. So why don’t I go down that route? Because the price of fixing the client-side IDs/validation is that the server-side model binding relies upon a single form  containing the main object and the collection(s) associated with it. My design used small repeating forms, one for each collection item (I was using a lot of Ajax and wanted to pass as little data as possible between server and client). Collection binding would solve the client-side problems I highlighted, but only at the cost of breaking the server-side model binding. Still – I think it’s worth looking at the alternative approach and seeing what it does for us – and what it doesn’t.

In order to bind a collection of complex objects, you need to set up editor templates and call them inside a for loop in the view.

So – first, what is an editor template?

Normally you call EditorFor() on simple data and get a standard HTML widget. Assigning EditorFor() to a string property will automatically generate a text input:

This code:

temp

Gives us this output:

However, we can create a view that contains many such elements and is designed to be the editor for a more complex object. In this case, I want to edit a Player object from my HTML5 game LaLaLadders. The first thing I need to do is add a new folder EditorTemplates under the Shared folder.

Like so much else in MVC, you use conventional names and locations to tell the system what to do. The next step is to add a view called Player[.cshtml/.vbhtml] underneath the folder:

Inside the file, add in the appropriate markup:

Now all we need to do is point the individual Player objects at this template inside a for loop in the main edit view and tell EditorFor() which template to use:

This then generates a form with all the players:

And each Player is given a unique id and name:

And these work perfectly well with client-side validation:

And the complex object is bound appropriately on the server:

So why does this not solve my problem?

The answer lies in the little ‘save’ button sitting after each individual player. It is completely redundant, because there is only one form. When I save, I am saving everything. But that’s not what I want. What I want – and what I have in the actual application – is repeating forms. I want to edit JUST the individual Player‘s details, not the whole object. I don’t want to be sending all that data back to the server – just the little bit I need.

So, no problem you might think. Just have the Player editor template contain a form that posts to a separate EditPlayer method and bind a single Player. Okay, let’s try that…

First, we have to move our iterator out of the main form so we don’t end up with nested forms:

Then we need to amend the Player editor so it contains a form that posts to EditPlayer:

We run it, and everything looks good. We end up with individual forms, each of which has the same iterated IDs and Names – e.g. Players_2_Name and Players[1].Name.

And that’s where we hit the problem. The model binder was fine with those names when it was dealing with the Players collection – but not now that we’re dealing with an individual Player. The result is our model is not bound on the server:

So, although you can get MVC to sort out its issues with client-side IDs and validation, you might not always want to. Sometimes, the cure can be worse than the disease. My LaLaLadders application would have been much more complicated, and would have used a heck of a lot more bandwidth, if I’d gone down this path… which is not to say that it isn’t the right solution in most circumstances.

The conclusion of all this? I still don’t think MVC handles repeating forms very well, but it does have some good tools for handling collections within a single form, if that’s what you’re looking for.

Kevin Rattan

For other related information, check out this course from Learning Tree:

Building Web Applications with ASP.NET MVC

Dependency Injection with Ninject and MVC 4

This week I uploaded a new version of www.cocktailsrus.com. I didn’t change all that much… just upgraded the server to .NET 4.5, upgraded MVC4 from beta to release, Entity Framework to 5.0, jQuery to 1.8.3, jQuery UI to 1.9.2 and jQuery Mobile to 1.2.0. Oh, and I finally made the move to storing the images on Amazon S3 (and, of course, I wrote a program to upload all the existing images ready for the new version).

So, not much change at all, then 🙂

I’ve been itching to make this change for a long time, but now that I’ve done it I have a potential problem: the production and development versions are using different data store types for images. I want to make sure that if I’m in debug mode I call the local file storage version of my PhotoRepository, and if I’m in release mode (and hence on the live server) I am using Amazon S3. There are all sorts of primitive ways I could manage this. I could, for example, change the using directive when I switch versions, going from cocktails.storage to cocktails.storage.amz. But all such approaches are fiddly and prone to human error. What I really want is an automated solution that picks the right object automatically without my intervention.

It’s time for dependency injection!

There are a number of DI frameworks available for .NET, but I decided to go with Ninject (since it looked a. reasonably simple and, b. sufficient for my purposes). Here is my design goal:

The application should automatically select the correct PhotoRepository depending upon whether it is in debug or release mode.

This is what I did to achieve it:

  1. Use NuGet to install the base Ninject framework and the MVC extensions into the MVC project

Don’t worry that it says MVC3 – it works in MVC 4 as well.

This will add a NinjectWebCommon file to App_Start. You could use this, but I did all my work inside Global.asax instead, so I excluded NinjectWebCommon from the project.

  1. Inherit Global.asax from NinjectHttpApplication instead of just HttpApplication and implement protected override Ninject.IKernel CreateKernel() and the override of OnApplicationStarted (which you might have to add yourself).
  2. Move all the code setting up routes etc. from the Application_Start routine to OnApplicationStarted and then remove Application_Start
  3. We’re now ready to start programming. Move to CreateKernal() and create a standard kernel. Then load the executing assembly.

  1. At this point, all the plumbing is in place – we can start setting up our dependencies. What I really want to do is set a dependency on the business/service layer – but for that I first need to create the dependency from the controller to the Service layer. So let’s add a mapping between IBeverageService and the BeverageService implementation:

Except, of course, I don’t actually have an IBeverageService interface because I haven’t needed one before now.

  1. So before I do anything else I have to refactor and create the appropriate interface

.

  1. Not only does that work, I can get Visual Studio to do all the heavy lifting for me. So I go right on and create interfaces for all of my Service classes.
  2. Now that I have interfaces, Ninject will look for the constructor with the most arguments in the specified implementation and use it to create the objects. So now I need to add constructors to all of my service methods so that Ninject can pass in the concrete implementations at runtime. I can then assign them to private read only variables. Like this:

  1. So now I need to tell Ninject which PhotoRepository implementation to use, and since I want different ones between development and production, our old friend conditional compilation can be really helpful here:

  1. Great. We can now pass through the appropriate PhotoRepository implementation to BeverageService. But first we have to add an appropriate constructor to our controller so that BeverageService itself is injected appropriately:

  1. And that’s it. Now when the application runs, Ninject is injecting the types specified inside my Gobal.asax – and giving me the appropriate image storage implementation. Here is the complete code for the CreateKernel() method with all the Service implementations assigned to the appropriate interfaces.

What do I like about this? The fact that my service layer does not even have to have a reference to either storage .dll, and that my application automatically switches to the appropriate back-end depending on the context.

What do I dislike about this? The fact that my UI, which previously only knew about the Service layer and was completely ignorant of the rest of the system now needs to have references to all the objects I might potentially inject. Is it a price worth paying? Definitely.

Kevin Rattan

For other related information, check out this course from Learning Tree:

Building Web Applications with ASP.NET MVC

Managing jQuery Mobile and ASP.NET MVC Compatibility Issues

jQuery Mobile is a great technology for producing mobile-friendly applications that work on multiple devices.

ASP.NET MVC is a great technology for creating elegant, scalable Web applications.

The two were made for each other: so much so that the Visual Studio 11 beta includes jQuery Mobile along with ASP.NET MVC and even provides a specific mobile template.

Sadly, however, jQuery Mobile and ASP.NET MVC don’t always play nicely together.

I was reminded of this forcefully last night when I uploaded the latest version of my personal website, Cocktails-R-Us (which I’ve now upgraded to ASP.NET MVC 4). The problems tend come down to two things: IDs and AJAX–and sometimes both together.

One issue that bit me this time around was an incompatibility between jQuery Mobile and the ASP.NET authentication framework. I tested the new version locally and everything worked. Everything seemed fine on the live server as well, until I tried to log in using a mobile browser and this happened:

screen grab of error

The problem was a simple one. JQuery Mobile uses AJAX navigation unless you tell it otherwise. The ASP.NET authentication system issues 302 redirects which are no problem to normal requests, but cause issues with AJAX. So the answer is to turn off AJAX. For that, all you have to do is add the attribute data-ajax=”false” to the <a> tag – which means doing the following in ASP.NET MVC:

code sample

A related problem with mixing jQuery Mobile and ASP.NET MVC is the very different assumptions each makes about how you will use the ID attribute.

One of the best things about jQuery Mobile is the elegant, animated page transitions. And one of the worst things about jQuery Mobile is the price you have to pay for them. The animated page transitions work by adding the new page into the existing DOM. That means that while only one page is visible at a time, the content of multiple pages is in the DOM simultaneously.

Now, it’s not as bad as it sounds. JQuery Mobile is not putting the entire page into the DOM – just the part you’ve identified as the content of the page. But it still leads to problems with IDs.

Let’s imagine that a user is going through a sequence of HTML forms that map to ASP.NET MVC controller methods. In those methods, the HTML form is automatically translated into an Entity. And let us assume that each of these entities has a Name property (in my case, for example, Cocktails, Beverages and Ingredients might have the Names ‘Old Cuban‘, ‘Rum’, ‘Mint’). The HTML forms would contain id=”Name” for each of these textboxes. Those IDs would work with validation (as we don’t have repeating forms on the same page) and everything would be fine. Except that with jQuery Mobile’s default behavior, the forms would all exist inside the current DOM, and we would end up with multiple repeating IDs and badly formed HTML.

A jQuery Mobile purist would no doubt say – well, just don’t use the IDs: you could manage without them on the client. Well, yes you could – but that would involve doing a lot of work on the server to reproduce behaviors that are given to you ‘out of the box’ with the MVC framework. The alternative is to turn off the nice AJAX transitions for pages with HTML forms. Unless, of course, you prefer to write your own Model Binder and/or View Engine for ASP.NET MVC to get around the problem.

Personally, I think I’ll just turn off the AJAX.

Kevin Rattan

For related information, check out these courses from Learning Tree:

jQuery: A Comprehensive Hands-On Introduction

Building Web Applications with ASP.NET MVC


Learning Tree International

.NET & Visual Studio Courses

Learning Tree offers over 210 IT training and Management courses, including a full curriculum of .NET training courses.

Free White Papers

Questions on current IT or Management topics? Access our Complete Online Resource Library of over 65 White Papers, Articles and Podcasts

Enter your email address to subscribe to this blog and receive notifications of new posts by e-mail.

Join 29 other followers

Follow Learning Tree on Twitter

Archives

Do you need a customized .NET training solution delivered at your facility?

Last year Learning Tree held nearly 2,500 on-site training events worldwide. To find out more about hosting one at your location, click here for a free consultation.
Live, online training

%d bloggers like this: