41

I have a partial view (control) that's used across several view pages, and I need to pass the name of the current view back to the controller - so if there's e.g. validation errors, I can re-draw the original view.

A workaround way to do it would be (in the controller methods)

var viewName = "Details"; // or whatever
ViewData["viewName"] = viewName;
return(View(viewName, customer));

and then in the partial itself, render it as

<input type="hidden" name="viewName" 
    value="<%=Html.Encode(ViewData["viewName"])%>" />

Question is - is there some property or syntax I can use to retrieve this directly instead of setting it from the controller? I've tried the obvious:

<input type="hidden" name="viewName" 
    value="<%=Html.Encode(this.Name)%>" />

but this doesn't work. What am I missing here?

Thanks.

Konamiman
  • 49,681
  • 17
  • 108
  • 138
Dylan Beattie
  • 53,688
  • 35
  • 128
  • 197
  • 1
    This is a bit of a stumper. I thought it should be possible since you can get the view name from the action result during controller testing... but I'm not clear on how to retrieve it from inside the View itself. Looking forward to an answer... – womp Aug 12 '09 at 21:36

10 Answers10

36

Well if you don't mind having your code tied to the specific view engine you're using, you can look at the ViewContext.View property and cast it to WebFormView

var viewPath = ((WebFormView)ViewContext.View).ViewPath;

I believe that will get you the view name at the end.

EDIT: Haacked is absolutely spot-on; to make things a bit neater I've wrapped the logic up in an extension method like so:

public static class IViewExtensions {
    public static string GetWebFormViewName(this IView view) {
        if (view is WebFormView) {
            string viewUrl = ((WebFormView)view).ViewPath;
            string viewFileName = viewUrl.Substring(viewUrl.LastIndexOf('/'));
            string viewFileNameWithoutExtension = Path.GetFileNameWithoutExtension(viewFileName);
            return (viewFileNameWithoutExtension);
        } else {
            throw (new InvalidOperationException("This view is not a WebFormView"));
        }
    }
}

which seems to do exactly what I was after.

Amirhossein Mehrvarzi
  • 18,024
  • 7
  • 45
  • 70
Haacked
  • 58,045
  • 14
  • 90
  • 114
  • 1
    just a follow up question since this is almost 2 years old: isn't there any simpler way of getting a Razor view name with ASP.NET MVC 3? – Leniel Maccaferri May 17 '11 at 20:48
  • can you help this poor soul :P ? http://stackoverflow.com/questions/6246082/mvc3-how-to-get-currently-executing-view-or-partial-view-programatically-inside/6246173#6246173 – Leniel Maccaferri Jun 09 '11 at 16:01
  • 3
    You can cast to 'BuildManagerCompiledView' instead of WebFormView. RazorView also extends from it. – Remco Ros Jan 27 '12 at 18:12
  • 2
    Ok, I am a bit lost here. Could you post an example of how you use this extension from within a view? How do I get an IView? I am using MVC 3. – NightOwl888 Aug 08 '12 at 02:32
17

I had the same problem and that's how I solved it:

namespace System.Web.Mvc
{
    public static class HtmlHelperExtensions
    {
        public static string CurrentViewName(this HtmlHelper html)
        {
            return System.IO.Path.GetFileNameWithoutExtension(
                ((RazorView)html.ViewContext.View).ViewPath
            );
        }
    }
}

Then in the view:

var name = Html.CurrentViewName();

or simply

@Html.CurrentViewName()
Konamiman
  • 49,681
  • 17
  • 108
  • 138
  • except this doesn't work if you include other pages via Html.Partial() because what you get is the including page, not the included – ekkis Feb 12 '15 at 20:47
9

If you just want the action name then this would do the trick:

public static string ViewName(this HtmlHelper html)
{
    return html.ViewContext.RouteData.GetRequiredString("action");
}
Daniel Elliott
  • 22,647
  • 10
  • 64
  • 82
  • 8
    I need the View name, not the action name. The view isn't contained in the route data anywhere; it's determined by the return value from the controller method. – Dylan Beattie Aug 13 '09 at 08:03
  • 2
    -1 See my comment to Anthony Johnston answer. This is totally misleading for novices!! – JotaBe Jun 19 '13 at 11:10
4

If you want to get the filename from within a partial view, this seems to work:

public static class HtmlHelperExtensions
{
    public static string GetViewFileName(this HtmlHelper html, object view)
    {
        return @"\\"+ view.GetType().FullName.Replace("ASP._Page_", "").Replace("_cshtml", ".cshtml").Replace("_", @"\\");
    }
}

And in the partial view, you should do something like this:

var filename = Html.GetViewFileName(this);

or this:

@Html.GetViewFileName(this)

Please do comment if this is not a good approach - any alternatives?

Miros
  • 527
  • 1
  • 3
  • 11
  • this works well for included pages. I would only recommend that one can get the current view's name like this `html.ViewDataContainer.GetType().FullName` which saves you from having to pass the view into the method – ekkis Feb 12 '15 at 21:18
4

Easiest solution is using ViewBag.

public ActionResult Index()
    {
        ViewBag.CurrentView = "Index";
        return View();
    }

On the cshtml page

@{
var viewName = ViewBag.CurrentView;
}

Or,

((RazorView)ViewContext.View).ViewPath
Mahib
  • 3,977
  • 5
  • 53
  • 62
  • 1
    But this is not a viable method when using a view that also renders partials. I was looking at this question due to a custom tool tip plugin im writing that is smart enough only using custom attribute on element, to get the current view, the property name, and retrieves meta data to be displayed in a "info" icon of element for a description, and business rules dependent upon another field for the end user. So two separate views may have a similar field name for two different view models within one view due to rendering partials. WILL WORK ON GENERAL VIEW RETURNED AT A TIME THOUGH. – Casey ScriptFu Pharr Dec 01 '17 at 04:02
4

If you are looking for solution for asp.net core you can use:

@System.IO.Path.GetFileNameWithoutExtension(ViewContext.View.Path)

This will return the current view name.

Postlagerkarte
  • 6,600
  • 5
  • 33
  • 52
0

Shouldn't you be using a validation method like Nerd Dinner implements?

That way you don't actually need to do all this and you can just return the View.

griegs
  • 22,624
  • 33
  • 128
  • 205
0

I had the same issue recently and the snippet of code I came up with solved my issue.

The only downfall is that Request.UrlReferrer could be null in some cases. Bit late but seemed to work for me and I covered all the bases of Request.UrlReferrer not being null.

 if (Request.UrlReferrer != null)
 {
      var viewUrl = Request.UrlReferrer.ToString();
      var actionResultName = viewUrl.Substring(viewUrl.LastIndexOf('/'));
      var viewNameWithoutExtension = actionResultName.TrimStart('/');
 }
0

You can use Razor:

in your View header

@{
    ViewData["Title"] = "YourViewName";    
}

in your View HTML

@{
   var _nameCurrentView = ViewContext.ViewData["Title"];
}

use in your html the variable @_nameCurrentView

  <li class="breadcrumb-item active">@_nameCurrentView</li>

or use in your action

  ViewData["Title"]
-3

Just wrote a blog thingy about this

http://www.antix.co.uk/A-Developers-Blog/Targeting-Pages-with-CSS-in-ASP.NET-MVC

  /// <summary>
  /// <para>Get a string from the route data</para>
  /// </summary>
  public static string RouteString(
      this ViewContext context, string template) {

   foreach (var value in context.RouteData.Values) {

    template = template.Replace(string.Format("{{{0}}}",
            value.Key.ToLower()),
            value.Value == null
                ? string.Empty
                : value.Value.ToString().ToLower());
   }

   return template;
  }

usage

<body class="<%= ViewContext.RouteString("{controller}_{action}") %>">

EDIT : Yes this is not going to give you the view name as the first comment states, it gives you the controller and action. But leaving it here as its valuable to know that it doesn't.

Anthony Johnston
  • 9,405
  • 4
  • 46
  • 57
  • This is an interesting idea and I like it. Only problem is that it is possible for a controller to conditionally return a view depending on some state, so this doesn't necessarily map to a specific view. – NightOwl888 Aug 08 '12 at 02:09
  • 5
    -1. As the previous comment states, it's very frequent to return a different view from an action depending on the outcome of the action. Or because several actions share a single view. So this is very unreliable. – JotaBe Jun 19 '13 at 11:08