1

I've got an ASP.NET MVC 4 application with a few sub-Areas. Ideally I'd like each Area to be as self-contained as possible, including all Content, Images, and so forth.

Is it possible to override the behavior of the "~" (tilde) character in resource paths within my Area View scripts to always refer to the Area root instead of the Application root?

Alternatively, is there another generic way to reference the Area root?

Example:

@* Should point to "~/Areas/MyNiftyArea/Images/logo.png": *@
@Url.Content("~/Images/logo.png");

Note: The rationale behind this is that I'm composing a single ASP.NET MVC web application from a few smaller applications, and I want to make sure the apps can be easily broken out again and rearranged as needed, including separating them back into their own applications down the road if necessary, without having to go through and split out all my resource/script files or change a bunch of explicitly-defined paths.

Of course, if there's a much better way to achieve this, I'm open to that as well.

Brian Lacy
  • 18,785
  • 10
  • 55
  • 73

1 Answers1

1

You can't change the behavior of Url.Content it basically goes to the following static code:

if (isAppRelative)
{
    string absoluteContentPath = VirtualPathUtility.ToAbsolute(contentPath, httpContext.Request.ApplicationPath);
    return GenerateClientUrlInternal(httpContext, absoluteContentPath);
}

However you can of course write your own helper and put it on the page.

What you will need to do it override ViewPage with your own class, do this by specifying @inherits on the page (or you can do it in ViewStart, see this blog for starting pointers http://develoq.net/2011/how-to-change-base-type-of-razor-view-engine-pages)

Now you can create your own UrlHelper property and make sure you override InitHelpers in your ViewPage. The original code does:

public virtual void InitHelpers()
{
    Ajax = new AjaxHelper<object>(ViewContext, this);
    Html = new HtmlHelper<object>(ViewContext, this);
    Url = new UrlHelper(ViewContext.RequestContext);
}

Replace the Url initializer with your own helper.

My personal opinion - this seems like a really big hammer and you will duplicate lots of resources and potentially get into bugs and area/area compatibility issues.

Based on your question below you can add a static GetAreaPath (see my comments to why it's not a framework piece):

public static string GetAreaPath()
{
    var routeData = HttpContext.Current.Request.RequestContext.RouteData;
    object areaobj;
    if (routeData.Values.TryGetValue("area", out areaobj))
    {
        string area = areaobj as string;

        if (area != null)
        {
            return @"~/Areas/" + area;
        }
    }

    return "~";
}
Yishai Galatzer
  • 8,791
  • 2
  • 32
  • 41
  • Is there any other way to determine the Area root path? Some built-in method or whatnot, so I could just call e.g. `@Url.Content(GetAreaRoot() + "/path/to/stuff.file")`? – Brian Lacy Apr 21 '14 at 17:27
  • hat really doesn't exist because 1. Area doesn't have a path just a namespace associated with it 2. For views it's based on paths in the RazorViewEngine "~/Areas/{2}/Views/{1}/{0}.cshtml" I updated the answer with a GetAreaPath() – Yishai Galatzer Apr 21 '14 at 19:44