Using Html.ActionLink and Url.Action(...) from inside Controller - asp.net-mvc

I want to write an HtmlHelper to render an ActionLink with pre-set values, eg.
<%=Html.PageLink("Page 1", "page-slug");%>
where PageLink is a function that calls ActionLink with a known Action and Controller, eg. "Index" and "Page".
Since HtmlHelper and UrlHelper do not exist inside a Controller or class, how do I get the relative URL to an action from inside a class?
Update: Given the additional three years of accrued experience I have now, here's my advice: just use Html.ActionLink("My Link", new { controller = "Page", slug = "page-slug" }) or better yet,
<a href="#Url.Action("ViewPage",
new {
controller = "Page",
slug = "my-page-slug" })">My Link</a>
Your extension method may be cute and short, but it adds another untested point-of-failure and a new learning requirement for hires without adding any real value whatsoever. Think of it as designing a complex system. Why add another moving part, unless it adds reliability (no), readability (little, once you read more docs), speed (none) or concurrency (none).

Not sure I actually understood your question clearly, but, let me try.
To create a HtmlHelper extension like you described, try something like:
using System;
using System.Web.Mvc;
using System.Web.Mvc.Html;
namespace Something {
public static class PageLinkHelper
{
public static string PageLink(
this HtmlHelper helper,
string linkText, string actionName,
string controllerName, object routeValues,
object htmlAttributes)
{
return helper.ActionLink(
linkText, actionName, controllerName,
routeValues, htmlAttributes);
}
}
}
As for your question on getting a URL from a class, depends on what kind of class you'll implement it. For example, if you want to get the current controller and action from a HtmlHelper extension, you can use:
string currentControllerName = (string)helper.ViewContext
.RouteData.Values["controller"];
string currentActionName = (string)helper.ViewContext
.RouteData.Values["action"];
If you want to get it from a controller, you can use properties/methods from the base class (Controller) to build the URL. For example:
var url = new UrlHelper(this.ControllerContext.RequestContext);
url.Action(an_action_name, route_values);

Related

Generate an absolute url in a razor view

I would like generate an absolute Url in a razor view
It might look something like this:
#Html.ActionLink("Register Now", "action", "controller",
new { area = "Area", id = #Model.Id }, null)
I have seen many attempts at this but have not found something that gives me the full link I need.
I don't believe there is a way to use Html.ActionLink to generate a link with an absolute URL. For example, using the Html.ActionLink from your question will produce the following HTML output:
#Html.ActionLink("Register Now", "Action", "Controller", new { #area = "Area", #id = Model.Id}, null)
// output: Register Now
To generate absolute URLs, I suggest implementing a custom extension method.
public static string AbsoluteActionUrl(this UrlHelper url, string actionName, string controllerName, object routeValues)
{
string scheme = url.RequestContext.HttpContext.Request.Url.Scheme;
return url.Action(actionName, controllerName, routeValues, scheme);
}
Of course, you will have to write the HTML markup yourself and use the extension to generate the URL for the href attribute, like so:
Register Now
You don't have to create the custom extension method, but then you would need to use a magic string to specify the scheme when using Url.Action.
The MSDN documentation for the Url.Action overload used above is available here. There are also other overloads available.

ASP.NET MVC Result Return Helper

I find myself needing to return various JSON results to the client from my controller actions. I have created static "helper" methods of the type ContentResult. I want to be able to reuse these helpers in multiple projects, so I've created them in their own class, and someday soon I'll move them to their own assembly.
Here is my question: Some of these return helpers need access to the controller context, so I've create then as extension methods on Controller. I like the way Html Helper methods are extension methods on the HtmlHelper class, but I can't find a suitable controller property similar the the Html property on the View class, so I just extended controller. Below is the code from on return helper. I want to know if there is a better way to do this.
public static ContentResult AJAXRedirect(this Controller cont, string action,
string controller, object routeValues)
{
string url = cont.Url.Action(action, controller, routeValues);
string json = "{{\"redirect\": \"{0}\" }}";
json = string.Format(json, url);
return new ContentResult
{
Content = json,
ContentType = "text/x-json",
ContentEncoding = Encoding.UTF8
};
}
You can use this code:
string url = cont.Url.Action(action, controller, routeValues);
return Json(new { redirect : url });
Extending Controller seems to be good way. Content(), View(), Json(), Empty() methods are also Controller extensions. You are adding your own.
EDIT
Sorry, I was actually wrong about extension methods. They are not extension methods. So it would be better if you used your own base Controller class with additional methods. Since you'll be using these methods inside of your classes, inheritance is the best solution. you can still share this class between projects.

Anonymous type as object, how can I access a property?

I am adding some functionality to the HtmlHelper-class. Basically I want to automatically disable links on a web page based on user privileges e t c.
So I have this function:
public static string ActionLinkWithPrivileges(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues)
{
return LinkExtensions.ActionLink(htmlHelper, linkText, actionName, routeValues);
}
The problem here is the routeValues-argument. Its usually created as an anonymous type so I dont know what to cast it to. This anonymous type often has a property named "id" but just writing routeValue.id gives me a compiler error.
Any help would be appreciated!
This should work :
RouteValueDictionary routeVals = new RouteValueDictionary(routeValues);
var value = routeVals["key"];
//RouteValueDictionary is under System.Web.Routing
either implement an interface or use reflection to get the PropertyInfo and then itterate through the property collection to get the right one.
you would of course need to tell the method the name of the property to get unless it's of a particular type.

Hiding content on view, based on controller authorization filters

Let's say I have a controller action that is restricted to only certain users, like this:
[Authorize(Roles="somerole")]<br />
public ActionResult TestRestricted() {
return View();
}
On a view, that is public to everyone I have a link to the action defined above:
<%= Html.ActionLink("Click here!", "TestRestricted") %>
What I'd like to do is hide the link for everyone that is not allowed perform the "TestRestricted"-action. Is there a way to check if the current user is authorized to use the corresponding action? Without defining any additional or duplicate access rules in addition to the authorization filter?
There is nothing in the MVC framework that can control permissions at such a granular level.
First Approach
This is by far the easiest approach. The drawback is having to assign the role to each action link.
What you could do, is write a Action HtmlHelper to control the permissions at a link level. Make sure you include the namespace System.Web.Mvc.Html.
public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string role)
{
MvcHtmlString link = new MvcHtmlString(string.Empty);
if (htmlHelper.ViewContext.RequestContext.HttpContext.User.IsInRole(role))
{
link = htmlHelper.ActionLink(linkText, actionName);
}
return link;
}
<%= Html.ActionLink("Click here!", "TestRestricted", "somerole") %>
Second Approach
You could use reflection to discover the action(method) being called. Once discovered a simple check of the attributes would tell you if the authorize attribute was present and what role it was set too.
This may help: http://weblogs.asp.net/rashid/archive/2009/09/06/asp-net-mvc-and-authorization-and-monkey-patching.aspx
I am also trying to find an answer to this question.....

ASP.NET MVC Using Render Partial from Within an Html Helper

I have an HtmlHelper extension that currently returns a string using a string builder and a fair amount of complex logic. I now want to add something extra to it that is taken from a render partial call, something like this ...
public static string MyHelper(this HtmlHelper helper)
{
StringBuilder builder = new StringBuilder();
builder.Append("Hi There");
builder.Append(RenderPartial("MyPartialView"));
builder.Append("Bye!");
return builder.ToString();
}
Now of course RenderPartial renders directly to the response so this doesn;t work and I've tried several solutions for rendering partials to strings but the all seem to fall over one I use the HtmlHelper within that partial.
Is this possible?
Because this question, although old and marked answered, showed up in google, I'm going to give a different answer.
In asp.net mvc 2 and 3, there's an Html.Partial(...) method that works like RenderPartial but returns the partial view as a string instead of rendering it directly.
Your example thus becomes:
//using System.Web.Mvc.Html;
public static string MyHelper(this HtmlHelper helper)
{
StringBuilder builder = new StringBuilder();
builder.Append("Hi There");
builder.Append(helper.Partial("MyPartialView"));
builder.Append("Bye!");
return builder.ToString();
}
I found the accepted answer printed out the viewable HTML on the page in ASP.NET MVC5 with for example:
#Html.ShowSomething(Model.MySubModel, "some text")
So I found the way to render it properly was to return an MvcHtmlString:
public static MvcHtmlString ShowSomething(this HtmlHelper helper,
MySubModel subModel, string someText)
{
StringBuilder sb = new StringBuilder(someText);
sb.Append(helper.Partial("_SomeOtherPartialView", subModel);
return new MvcHtmlString(sb.ToString());
}
You shouldn't be calling partials from a helper. Helpers "help" your views, and not much else. Check out the RenderAction method from MVCContrib (if you need it now) or MVC v2 (if you can wait a few more months). You'd be able to pass your model to a standard controller action and get back a partial result.

Resources