Best asp.net-mvc questions in September 2011

A smart way to handle Return URLs in an MVC environment

9 votes

A problem I come up against again and again is handling redirection to the previous page after a user runs some action such as clicking a 'Back To ...' link or saving the record they are editing.

Previously whenever I have needed to know what page to return to, I would provide a returnURL parameter to my current view.

http://blah.com/account/edit/1?returnURL="account/index"

This isn't a very clean way of handling this situation, as sometimes the return URL contains parameters such as search strings, etc, which have to be included in the URL.

http://blah.com/account/edit/1?returnURL="account/index?search="searchTerm""

Also, this creates an issue when a user can go another page forward before coming back to the page with the returnURL because you have to pass the returnURL through all visited pages.

Simply calling the browser's Back functionality isn't really sufficient either, because you might want the page to refresh, e.g. to show the edits you just saved in the previous page.

So my question is, has anyone found a smart way to handle this kind of situation, specifically in an MVC environment?

Note: I am using ASP .NET MVC so if possible I'd like answers to pertain to that, however any ideas are welcome.

What's wrong with setting a cookie, or using a session variable? The only reason you wouldn't is if you don't control the page that calls into you, in which case your only options are query strings, post values, or referrer.

Can I assume that the order I send values over POST will be model bound to an array in the same order in Asp.net MVC?

9 votes

I'm am working on having a screen that allows the user to change the order of items, and when the user clicks on the "Save" button my javascript will look at the order of <li> items, and in the order it finds them it will form an array with an id value and send it back to my application. I expect the POST data to look like:

stepIds=5&stepIds=2&stepIds=1

This means that the steps are in the order of #5, then #2, and lastly #1. In my Asp.Net MVC application I plan to catch it with:

public virtual ActionResult Reorder(short[] stepIds) { }

My question is, will Asp.net MVC ALWAYS form the stepIds array in the same order that values are specified in the POST string, or do I need to do a more complicated POST in order to ensure the order the user picks is the order the server sees?

No, you cannot rely on the order. The way this is implemented in ASP.NET 4.0 it will indeed preserve the order but this might change in future versions. You may look at the HttpValueCollection.FillFromString private method with Reflector to see how it is implemented.

The only reliable way to guarantee order is this:

stepIds[0]=5&stepIds[1]=2&stepIds[2]=1

.NET MVC3 Preferred Model Initializiation

6 votes

I have been working in MVC recently, and I am curious about what the best way to initialize my view models is. Should I be mapping it directly in the controller, or should I be initializing the properties in a constructor for the view model. Also, when having lists, is this better practice since you will not have to repopulate them when there is a validation error.

For example, if i had the following model:

public FooBarViewModel
{
    public int FooBarId { get; set; }
    public string SomeInitialProperty1 { get; set; }
    public string SomeInitialProperty2 { get; set; }
    public string SomeInitialProperty3 { get; set; }
    public string SomeInitialProperty4 { get; set; }
    public int FooId { get; set; }
    public int BarId { get; set; }
    public IEnumerable<Foo> Foos { get; set; }
    public IEnumerable<Bar> Bars { get; set; }
}

and then the controller:

public MyController : Controller
{
    [HttpGet]
    public ActionResult FooBar(int foobarId)
    {
        var foobar = _fooBarRepository.GetById(foobarId);
        var model = new FooBarViewModel
                        {
                            FooBarId = foobar.Id;
                            SomeInitialProperty1 = foobar.SomeInitialProperty1;
                            SomeInitialProperty2 = foobar.SomeInitialProperty2;
                            SomeInitialProperty3 = foobar.SomeInitialProperty3;
                            SomeInitialProperty4 = foobar.SomeInitialProperty4;
                            Foos = foobar.Foos.ToList();
                            Bars = foobar.Bars.ToList();
                        }

        return View(model);
    }

    [HttpPost]
    public ActionResult FooBar(FooBarViewModel model)
    {
        if (ModelState.IsValid)
        {
             //process model
             return RedirectToAction("Index");
        }

        var foobar = _fooBarRepository.GetById(model.FoobarId);
        model.Foos = foobar.GetFoos.ToList();
        model.Bars = foobar.GetBars.ToList();
        return View(model);
    }
}

or should I do it in my model:

public FooBarViewModel
{
    public int FooBarId { get; set; }
    public string SomeInitialProperty1 { get; set; }
    public string SomeInitialProperty2 { get; set; }
    public string SomeInitialProperty3 { get; set; }
    public string SomeInitialProperty4 { get; set; }
    public int FooId { get; set; }
    public int BarId { get; set; }

    public IEnumerable<Foo> Foos 
    { 
        get { return _foos; }
    }
    private IEnumerable<Foo> _foos;

    public IEnumerable<Bar> Bars
    { 
        get { return _bars; }
    }
    private IEnumerable<Bar> _bars;

    public MyViewModel(FooBar foobar)
    {
        FooBarId = foobar.Id;
        SomeInitialProperty1 = foobar.SomeInitialProperty1;
        SomeInitialProperty2 = foobar.SomeInitialProperty2;
        SomeInitialProperty3 = foobar.SomeInitialProperty3;
        SomeInitialProperty4 = foobar.SomeInitialProperty4;
        _foos = foobar.Foos.ToList();
        _bars = foobar.Bars.ToList();
    }
}

then my controller:

public MyController : Controller
{
    [HttpGet]
    public ActionResult FooBar(int foobarId)
    {
        var foobar = _fooBarRepository.GetById(foobarId);
        var model = new FooBarViewModel(foobar);

        return View(model);
    }

    [HttpPost]
    public ActionResult FooBar(FooBarViewModelmodel)
    {
        if (ModelState.IsValid)
        {
             //process model
             return RedirectToAction("Index");
        }

        return View(model);
    }
}

Which is the preferred convention in MVC and why is it the best practice? Also, reasons why to choose one over the other? Thanks in advance.

By default, I do not believe MVC will use the DependencyResolver to create the instance of your view model on postback. As such, it will only create a model with a parameterless constructor. This makes it less easy to initialize the object in the constructor.

You could create a custom model binder that created the objectt through DependencyResolver, but then you are deviating from normal practice.

I prefer to inialize my view models with AutoMapper.

When to split an MVC view into two?

6 votes

I discussed best practices in MVC the other day with a colleague and he asked me how to best separate views. He was maintaining an MVC solution which had a common input form with a controller with two actions, a get action, and a post action. Both actions were returning the same view, which was filled with inline logic, and conditionals checking whether it was a post or a get.

What is the best solution for this situation? Should the view be split into two separate views? I guess it depends on how much logic is in there, but when is too much? Is there a way to quantify when you can motivate the refactoring into two views?

I would definitely separate something like that into two separate views and then use partial views for the parts that are in common between them.

Composition, without inheritance and without conditional logic, is nearly always the cleaner, clearer, more maintainable way to go when it comes to planning Views.

CSS alignment problem

5 votes

How can I make my registration fields like this

enter image description here

How can I achieve this via CSS? I mean, that my textboxes should be aligned from label's end to the page's end...

EDIT

Here is my view part

<div id="member-search">

<h5>Last Name:</h5>
@Html.TextBox("member-last-name")
</div>
<div>
<h5>Pass:</h5>
@Html.TextBox("member-pass")
</div>

<input type="submit" value="Search" class="button"/>
</div>

In CSS I tried a lot, but with no success. width:auto doesn't help and I don't find solution for this. Thanks for help.

With changes to your view you can achieve this. My answer is based on the following answer: How to make text input box to occupy all the remaining width within parent block?

You can look at the modified version of the answer at http://jsfiddle.net/626B2/63/

HTML:

<div id="parent">
    <div id="inner">
        <label>UserName</label><span><input id="text" type="text" /></span>
    </div>
    <div id="inner">
        <label>pass</label><span><input id="text" type="text" /></span>
    </div>
    <input id="submit" type="button" value="Submit" />
</div>

CSS:

#inner {
    display: table;
    width: 100%;
}
label {
    display: table-cell;
    white-space:nowrap;

}
span {
    display: table-cell;
    width: 100%;
    padding: 0px 10px;
}
#text {
    width: 100%;
}

ASP.net MVC get current viewengine

5 votes

Is it possible to get the currently used viewengine from lets say the ControllerContext or the viewengine collection? I would like to be able to do say the following Viewengines.GetCurrent. I know that i can make an extensions for that method but i have no idea on how to implement this.

You can use ViewEngineCollection to look up the ViewEngine associated with a particular view.

ViewEngineResult result = ViewEngines.Engines.FindView(controllerContext,
                                                       "myView","myMaster");
IViewEngine viewEngine = result.ViewEngine;

See here for more info.

Ninject + ASP.net MVC + Entity Framework - when is my context disposed?

5 votes

I am using Ninject in my MVC 3 application and one of my dependencies is on Entity Framework:

interface IFooRepository
{
    Foo GetFoo(int id);
}

public EFFooRepository : IFooRepository
{
    private FooDbContext context;

    public EFFooRepository(FooDbContext context)
    {
        this.context = context;
    }
 }

I set up a binding like so in Ninject, so if I have more than one dependency and they both need a data context they end up sharing the same context:

Bind<FooDbContext>().ToSelf().InRequestScope();

I am uncertain of when my context will be disposed. Since I am not the one that instantiates it, will it ever get disposed of or will it just get disposed of when it is garbage collected? Does Ninject know to Dispose of anything when it is done with it?

If the FooDbContext implements IDisposable, Ninject will automatically call the Dispose method on it at the end of the request.

Here's how you can verify it:

  1. Create a new ASP.NET MVC 3 application using the default template
  2. Install the Ninject.Mvc3 NuGet package
  3. Have the following:

    public interface IFooRepository
    {
    }
    
    public class FooDbContext: IDisposable
    {
        public void Dispose()
        {
            throw new NotImplementedException();
        }
    }
    
    public class EFFooRepository : IFooRepository
    {
        private FooDbContext _context;
    
        public EFFooRepository(FooDbContext context)
        {
            _context = context;
        }
     }
    
    public class HomeController : Controller
    {
        private readonly IFooRepository _repo;
    
        public HomeController(IFooRepository repo)
        {
            _repo = repo;
        }
    
        public ActionResult Index()
        {
            return View();
        }
    }
    
  4. Add the following in the RegisterServices method of ~/App_Start/NinjectMVC3.cs:

    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<FooDbContext>().ToSelf().InRequestScope();
        kernel.Bind<IFooRepository>().To<EFFooRepository>();
    }
    
  5. Run the application. As expected at the end of the request, the FooDbContext instance is disposed and the NotImplementedException exception is thrown.

Infinite URL Parameters for ASP.NET MVC Route

4 votes

I need an implementation where I can get infinite parameters on my ASP.NET Controller. It will be better if I give you an example :

Let's assume that I will have following urls :

example.com/tag/poo/bar/poobar
example.com/tag/poo/bar/poobar/poo2/poo4
example.com/tag/poo/bar/poobar/poo89

As you can see, it will get infinite number of tags after example.com/tag/ and slash will be a delimiter here.

On the controller I would like to do this :

foreach(string item in paramaters) { 

    //this is one of the url paramaters
    string poo = item;

}

Is there any known way to achieve this? How can I get reach the values from controller? With Dictionary<string, string> or List<string>?

NOTE :

The question is not well explained IMO but I tried my best to fit it. in. Feel free to tweak it

Like this:

routes.MapRoute("Name", "tag/{*tags}", new { controller = ..., action = ... });

ActionResult MyAction(string tags) {
    foreach(string tag in tags.Split("/")) {
        ...
    }
}

Sending a parameter to the controller in ASP MVC 2

4 votes

I am writing an area for administering several subsites, almost all of the functionality will be the same across each site (add/edit/remove pages etc) and my repository on instantiation takes the SiteIdentity so all the data access methods are agnostic in relation to this. The problem I have at the moment is trying to make my action methods also agnostic.

The URL pattern I want to use is along the lines of:

"ExternalSite/{identity}/{controller}/{action}/{id}"

A naive approach is to have each action take the identity parameter, but this means having to pass this in to my repository on each action as well as include it in the ViewData for a couple of UI elements. I'd much rather have this something that happens once in the controller, such as in its constructor.

What is the best way to do this? Currently the best I can come up with is trying to find and cast identity from the RouteData dictionary but part of me feels like there should be a more elegant solution.

It sounds like you want to use OnActionExecuting or a Custom ModelBinder to do that logic each time you have a specific parameter name (also known as a RouteData dictionary key).

  1. Creating a custom modelbinder in ASP.NET MVC
  2. Creating an OnActionExecuting method in ASP.NET MVC, Doing Serverside tracking in ASP.NET MVC

How do I re-authenticate a user in an ASP.Net MVC 3 _Intranet_ application?

4 votes

Let me explain: the application is already using Windows integrated security, not Forms. What I am trying to accomplish is a so called "step-up" authentication, or "force re-authentication" for the following scenario:

  1. the user is browsing the site doing common, trivial stuff
  2. suddenly, the user has to do a sensitive action such as authorizing a ressource allocation or confirming a car loan or something similar
  3. the user is prompted for the credential before (s)he's redirected to the sensitive page, in a manner similar to SharePoint's "Sign In as a Different User"
  4. if, and only if, the credentials entered are the same as for the currently logged-in user the application proceeds to the sensitive area.

This would prevent the following 2 issues:

  1. The user goes for a meeting or a coffee and forgets to lock the workstation and a colleague uses the session to access the sensitive area
  2. The user enters the credentials of his or her boss (because, let's say he peeked over the boss' sholder) to access the sensitive area.

I know, some would look at this as "being paranoid", but also some would say it's common sense and should be build in a framework somewhere (jQuery or .NET)

I would really appreciate any input. Thank you!

Have the form send the credentials along with the request to perform the action, i.e., some actions require that you provide username/password. Use the PrincipalContext ValidateCredentials method to ensure that the proper credentials have been entered and check that the username supplied matches the current username in the User.Identity object.

public ActionResult SensitiveAction( SensitiveModel model, string username, string password )
{
    using (var context = new PrincipalContext(ContextType.Domain))
    {
         if (!string.Equals(this.User.Identity.Name,username,StringComparison.OrdinalCaseIgnore)
             || !context.ValidateCredentials(username,password))
         {
              return View("PermissionDenied");
         }
    }

    ...
}

How do I use my HTTP handlers for selected paths and MVC handler for the rest?

4 votes

I have an MVC2 application. I also have a set of ready HTTP handlers that derive from System.Web.IHttpHandler. How do I use them together?

I tried the following in web.config:

<system.webServer>
    <!--other stuff-->
        <handlers>
            <add name="MyCustomHandler" verb="GET" path="MySpecificPath*" type="CustomHandling.CustomHttpHandlerBase, CustomHAndlingAssembly"/>
            <add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.mvc" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"/>
        </handlers>
</system.webServer>

yet control never reaches my handler and MVC handler is used for all requests.

How do I use my handler for one specific path and MVC handler for all other paths?

I believe that you need to ignore those specific paths from routes collection in application start. For example,

routes.IgnoreRoute("MySpecificPath/{*pathInfo}");

Otherwise UrlRoutingModule will match with the route and then http handler will be located via IRouteHandler for that route.

See this article for more info about mixing ASP.NET WebForms with ASP.NET MVC .