citizenmatt
citizenmatt

Reputation: 18573

Why does MVC look for .aspx and .ascx for both full and partial views?

I've just been bitten by a problem where I have a view (FindUser.aspx) trying to render a partial view (FindUser.ascx). The default search paths for views look for a file named after the view in a variety of folders. Rather surprisingly, for views, it looks for a file with the extensions of .aspx or .ascx. And the partial views use the same list.

Because I've got the two files named the same, the view resolution repeatedly finds the page first, and falls into an endless loop.

I know I can fix this either by calling the view and the partial view different names, or by changing my search locations to be .aspx only for views and .ascx only for partial views.

My question is why does MVC default to looking at both extensions? It seems to make more sense that a view == a page == .aspx and a partial view == a control == .ascx. So why muddy the waters?

Upvotes: 4

Views: 2466

Answers (6)

Andrew Dunkman
Andrew Dunkman

Reputation: 1131

If you're using Areas, you'll have to add additional LocationFormats in the constructor:

public class ExtensionBasedWebFormViewEngine : WebFormViewEngine
{
  public ExtensionBasedWebFormViewEngine()
  {
     ViewLocationFormats = new[] {"~/Views/{1}/{0}.aspx", "~/Views/Shared/{0}.aspx"};
     AreaViewLocationFormats = new[] {"~/Areas/{2}/Views/{1}/{0}.aspx", "~/Areas/{2}/Views/Shared/{0}.aspx"};

     PartialViewLocationFormats = new[] {"~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.ascx"};
     AreaPartialViewLocationFormats = new[] { "~/Areas/{2}/Views/{1}/{0}.ascx", "~/Areas/{2}/Views/Shared/{0}.ascx" };
  }
}

Upvotes: 0

Andrew Stanton-Nurse
Andrew Stanton-Nurse

Reputation: 6294

I think that the way to avoid the problem you're having is to use different view names. You probably shouldn't have two views whose file name differs only in extension. However, if you really want a strict Page = View, Control = Partial mapping, just create your own ViewEngine by inheriting from WebFormViewEngine and change the view location formats:

public class MyWebFormViewEngine : WebFormViewEngine {
    public MyWebFormViewEngine() {
        base.ViewLocationFormats 
          = new string[] {"~/Views/{1}/{0}.aspx", "~/Views/Shared/{0}.aspx" };
        base.PartialViewLocationFormats 
          = new string[] { "~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.ascx" };
    }
}

Then configure it as your View Engine in Application_Start():

// Call this method during Application_Start to setup your view engine
internal static void SetupViewEngines() {
    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new MyWebFormViewEngine());
}

Upvotes: 2

Arnis Lapsa
Arnis Lapsa

Reputation: 47567

Reason
View == UserControl in ASP.NET MVC.

Fix
Use different names.

Tip
It`s common convention to name usercontrols with underscore prefix.

Upvotes: 0

swilliams
swilliams

Reputation: 48890

You can give MVC the direct path when rendering Views. Say I have a Foo.aspx in my Home folder and a Foo.ascx partial view in Shared. In your action method you can do either:

return View("~/Views/Shared/Foo.ascx"); // or
return View("~/Views/Home/Foo.aspx");

And it will get the proper one you're looking for.

Upvotes: 1

tvanfosson
tvanfosson

Reputation: 532435

For what it's worth I append "Control" to the name of all of my .ascx ViewUserControls. So I would have FindUser.aspx and FindUserControl.ascx. Doesn't solve the problem but it helps you to avoid it by avoiding naming collisions.

Upvotes: 1

Çağdaş Tekin
Çağdaş Tekin

Reputation: 16651

Because partial or not, a view is still a view. Having FindUser.aspx and FindUser.ascx is the same as having two regular views with the same name.

Upvotes: 3

Related Questions