ASP.NET MVC - HTML Extension method building a URL or link - asp.net-mvc

Consider an extension method whose purpose is to either:
render an <a> tag
on some condition, just return a string without a link
Question: in an extension method, how can you leverage the proper routing logic with Route Values, etc. rather than hardcoding the string. I suspect HtmlHelper.GenerateRouteLink is part of the solution, but please suggest the best way to achieve this.
public static string CreateUserLink(this HtmlHelper html, string userAcctName)
{
if (string.IsNullOrEmpty(userAcctName))
return "--Blank--";
//some lookup to A.D.
DomainUser user = ADLookup.GetUserByAcctName(userAcctName);
if (user == null)
return userAcctName;
//would like to do this correctly!
return string.Format("<a href='/MyAppName/User/View/{0}' title='{2}'>{1}</a>"
, user.Mnemonic, user.DisplayName, user.Location);
//normally returns http://mysite.net/MyAppName/User/View/FOO
}
More info:
using ASP.NET MVC 1.0

I just had to do something similar to this yesterday. There may be a slicker way to do it, but it helps me to see exactly what is going on, so I don't assume anything.
public static string CreateUserLink(this HtmlHelper html, string userAcctName)
{
if (string.IsNullOrEmpty(userAcctName))
return "--Blank--";
//some lookup to A.D.
DomainUser user = ADLookup.GetUserByAcctName(userAcctName);
if (user == null)
return userAcctName;
RouteValueDictionary routeValues = new RouteValueDictionary();
routeValues.Add("controller", "User");
routeValues.Add("action", "View");
routeValues.Add("id", user.Mnemonic);
UrlHelper urlHelper = new UrlHelper(html.ViewContext.RequestContext);
TagBuilder linkTag = new TagBuilder("a");
linkTag.MergeAttribute("href", urlHelper.RouteUrl(routeValues));
linkTag.MergeAttribute("title", user.Location);
linkTag.InnerHtml = user.DisplayName;
return linkTag.ToString(TagRenderMode.Normal);
}

would this work?
public static string CreateUserLink(this HtmlHelper html, string userAcctName)
{
if (string.IsNullOrEmpty(userAcctName))
return "--Blank--";
//some lookup to A.D.
DomainUser user = ADLookup.GetUserByAcctName(userAcctName);
if (user == null)
return userAcctName;
return html.ActionLink(user.DisplayName, "user", "View", new {title=user.Location});
//normally returns http://mysite.net/MyAppName/User/View/FOO
}

My experience with GenerateRouteLink has been an uphill battle. It's been a while since I messed with it but if it's the Method I'm thinking of Microsoft has made it "internal" so you can't access and use it outside the MVC assembly. There are a number of workarounds that I played with and didn't really like.
What I ended up doing to avoid hard coding the url in my helper methods is have it accept a 'string url' parameter and use Url.Action in my view when I call the helper method. It's not the cleanest but it's a workaround that worked well for me.
<%= Html.CreateUserLink("userAcctName", Url.Action("Home", "Controller") %>

Related

Dynamically extract information from FluentSecurity configuration

I'm working on an ASP.NET MVC Website that uses FluentSecurity to configure authorizations. Now we need a custom ActionLink Helper which will be displayed only if the current user has access to the targeted action.
I want to know if there is a way to know dynamically, from FluentSecurity Configuration (using SecurityConfiguration class for example), if the current logged user has access to an action given her name (string) and her controller name (string). I spend a lot of time looking in the source code of FluentSecurity https://github.com/kristofferahl/FluentSecurity but with no success.
For example:
public bool HasAccess(string controllerName, string actionName) {
//code I'm looking for goes here
}
Finally, i will answer myself may this will help another one.
I just emulate the OnAuthorization method of the HandleSecurityAttribute class. this code works well:
public static bool HasAccess(string fullControllerName, string actionName)
{
ISecurityContext contx = SecurityContext.Current;
contx.Data.RouteValues = new RouteValueDictionary();
var handler = new SecurityHandler();
try
{
var result = handler.HandleSecurityFor(fullControllerName, actionName, contx);
return (result == null);
} catch (PolicyViolationException)
{
return false;
}
}

Redirect page in c# mvc

I have link
http://localhost:3163/PaymentOrder?AgentCode=&InvoiceNo=&AgentName=&FromDate=&fromDate=12%2F11%2F2013&FromDate=12%2F11%2F2013+9%3A08%3A01+SA&toDate=12%2F11%2F2013
after click button "Delete" the page should be redirect to "Index"
return RedirectToAction("Index","PaymentOrder");
But i want keep link same as first, i don't know what method, please help me. thanks
I can fix it, i save session in
public ActionResult Index{
Session["LastPage"] = Request.Url.ToString();
}
after I'm
return Redirect(Session["LastPage"] as String);
You can pass the query strings to the third parameter of RedirecToAction
return RedirectToAction("Index","PaymentOrder", new { fromDate = model.FromDate });
Or pass the entire model as well, that contains the properties similar to your query strings
return RedirectToAction("Index","PaymentOrder", new { paymentModel = model });
As your query string is quite long, it would probably be better to write an extension method and use that instead, to keep your controllers thin. I haven't tested this, but something like this should work:
public static RouteValueDictionary ToRouteDictionary(this NameValueCollection nameValues)
{
if (nameValues == null || nameValues.HasKeys() == false)
return new RouteValueDictionary();
var routeValues = new RouteValueDictionary();
foreach (var key in nameValues.AllKeys)
routeValues.Add(key, nameValues[key]);
return routeValues;
}
Then in your controller:
return RedirectToAction("Index","PaymentOrder", Request.QueryString.ToRouteDictionary());
Just don't redirect but return the view, the URL will remain the same.

working with Actionfilter

I have never worked with actionfilter so i dont really know how to use it, ive done som reseach but i dont completly understand it. But basicly im going to create a new controller, and i want my _Viewstart.cshtml to use this controller. The problem is that i dont know how to use this code to an actionfilter and then call this controller in _viewstart.
The code that i want in my controller is.
var TemplateIDSession = Session["TemplateID"];
if (TemplateIDSession != null)
{
int tempID = (int)TemplateIDSession;
var template = servicetemp.GetEntry(tempID);
var servicetemp = ServiceFactory.Instance.CreateTemplateService();
Response.ContentType = "text/css";
return RazorEngine.Razor.Parse(System.IO.File.ReadAllText(Server.MapPath("Content/Site.css")));
I think you should go about this in a different way, by using a HTML Helper for the CSS, like so:
public static class Helpers
{
public static string OrganizationStyleTemplate(this HtmlHelper html)
{
TagBuilder tagBuilder = new TagBuilder("style");
var templateIDSession = HttpContext.Current.Session["TemplateID"];
if (TemplateIDSession != null)
{
// retrieve your css from the database and insert it into the tag
tagBuilder.InnerHtml = dbObject.CSSYouveStored;
}
return tagBuilder.ToString(TagRenderMode.Normal);
}
}
Then usage would be like so:
#Html.OrganizationStyleTemplate()
P.S. If you need to analyze if the user is authenticated within that method, use:
HttpContext.Current.Request.IsAuthenticated

How to use ASP.NET MVC Html Helpers from a custom helper?

I have several pages listing search results, for each result I would like to display I want to create a custom View Helper in order to avoid duplicating the display code.
How do I access the convenient existing view helpers from my custom view helper? I.e. in my custom view helper I would like to use Url.Action(), Html.ActionLink, etc. How do I access them from my custom view helper?
using System;
namespace MvcApp.Helpers
{
public class SearchResultHelper
{
public static string Show(Result result)
{
string str = "";
// producing HTML for search result here
// instead of writing
str += String.Format("{1}", result.id, result.title);
// I would like to use Url.Action, Html.ActionLink, etc. How?
return str;
}
}
}
using System.Web.Mvc gives access to HtmlHelpers, but non of the convenient methods like ActionLink seem to be present.
This example should help you. This helper renders different link text depending on whether the user is logged in or not. It demonstrates the use of ActionLink inside my custom helper:
public static string FooterEditLink(this HtmlHelper helper,
System.Security.Principal.IIdentity user, string loginText, string logoutText)
{
if (user.IsAuthenticated)
return System.Web.Mvc.Html.LinkExtensions.ActionLink(helper, logoutText, "Logout", "Account",
new { returnurl = helper.ViewContext.HttpContext.Request.Url.AbsolutePath }, null);
else
return System.Web.Mvc.Html.LinkExtensions.ActionLink(helper, loginText, "Login", "Account",
new { returnurl = helper.ViewContext.HttpContext.Request.Url.AbsolutePath }, null);
}
EDIT:
All you would need to do to to access the Url.Action() method would be to replace the this HtmlHelper helper param with something like this UrlHelper urlHelp and then just call urlHelp.Action(...
Hope this helps.
A simple gravatar html helpler, your class needs to be static also.
public static string GetGravatarURL(this HtmlHelper helper, string email, string size, string defaultImagePath)
{
return GetGravatarURL(email, size) + string.Format("&default={0}", defaultImagePath);
}
you can extend the default HtmlHelper and UrlHelper just with an extension method (so you have the xxxHelper as first param in your method).
Or you can just create your base view with the method you want and use the Html or URL variable of the view.
In my opinion, you shouldn't be trying to use ActionLink within code. The whole concept of MVC is to separate logic from display, so you should try to stick with that.
I would suggest you pass the result object through to the view (maybe through ViewData) and then parse the result inline within the view. e.g.
<%= Html.ActionLink(result.title,"/showresult/" + result.id, "myController") %>

Asp.Net MVC - Best approach for "dynamic" routing

I am trying to come up with an approach to create "dynamic" routing. What I mean, exactly, is that I want to be able to assign the controller and action of a route for each hit rather than having it mapped directly.
For example, a route may look like this "path/{object}" and when that path is hit, a lookup is performed providing the appropriate controller / action to call.
I've tried discovering the mechanisms for creating a custom route handler, but the documentation / discoverability is a bit shady at the moment (I know, its beta - I wouldn't expect any more). Although, I'm not sure if thats even the best approach and perhaps a controller factory or even a default controller/action that performs all of the mappings may be the best route (no pun intended) to go.
Any advice would be appreciated.
You can always use a catch all syntax ( I have no idea if the name is proper).
Route:
routeTable.MapRoute(
"Path",
"{*path}",
new { controller = "Pages", action = "Path" });
Controller action is defined as:
public ActionResult Path(string path)
In the action for controller you will have a path, so just have to spilt it and analyse.
To call another controller you can use a RedirectToAction ( I think this is more proper way). With redirection you can set up a permanent redirectionfor it.
Or use a something like that:
internal class MVCTransferResult : RedirectResult
{
public MVCTransferResult(string url) : base(url)
{
}
public MVCTransferResult(object routeValues)
: base(GetRouteURL(routeValues))
{
}
private static string GetRouteURL(object routeValues)
{
UrlHelper url = new UrlHelper(
new RequestContext(
new HttpContextWrapper(HttpContext.Current),
new RouteData()),
RouteTable.Routes);
return url.RouteUrl(routeValues);
}
public override void ExecuteResult(ControllerContext context)
{
var httpContext = HttpContext.Current;
// ASP.NET MVC 3.0
if (context.Controller.TempData != null &&
context.Controller.TempData.Count() > 0)
{
throw new ApplicationException(
"TempData won't work with Server.TransferRequest!");
}
// change to false to pass query string parameters
// if you have already processed them
httpContext.Server.TransferRequest(Url, true);
// ASP.NET MVC 2.0
//httpContext.RewritePath(Url, false);
//IHttpHandler httpHandler = new MvcHttpHandler();
//httpHandler.ProcessRequest(HttpContext.Current);
}
}
However this method require to run on IIS or a IIS Expres Casinni is not supporting a Server.Transfer method

Resources