MVC Shared Layout Parameter to Logoff - asp.net-mvc

I use a shared layout and I am trying to pass the current location to the logoff method, but I'm not sure how to do it. I've tried: Request.Url.OriginalString, Request.Url.Scheme and in the logoff method the parameter type I put the parameter type as string but it isn't working. Anyone have any idea?
Log Off Button on my layout page
<a onclick="location.href = '#Url.Action("Logoff", "Account", "Request.Url.Scheme")'"><span class="logOffSpan">Sign Out</span
public ActionResult LogOff(string url)
{
var local = Convert.ToBoolean(ConfigurationManager.AppSettings["local"]);
if (local)
{
FormsAuthentication.SignOut();
}
else
{
CasAuthentication.SingleSignOut();
}
Session.Clear();
return to Redirect("Some Method","Some Controller");//I want the user to just return to whatever page they were just on when they clicked log off
}

You can use Request.Url.AbsoluteUri to get the absolute URL of the current page.
Then you can use this overload of #Url.Action method which takes a RouteValueDictionary object as third parameter to build the route params / querystrings.
public virtual string Action (string actionName,
string controllerName,
RouteValueDictionary routeValues);
So your view code will be
<a href="#Url.Action("Logoff", "Account", new { url = Request.Url.AbsoluteUri })">
<span class="logOffSpan">Sign Out</span>
</a>
This will basically generate the anhcor tag with the href attribute value set to /Account/Logogg?url={yourCurrentPageUrl}, where {yourCurrentPageUrl} will be replaced with your current page URL.
Now in your action method you can use the Redirect method with this aboslute URL value which will be available in your url parameter.
public ActionResult LogOff(string url)
{
// Your existing logic
return Redirect(url);
}

Related

How to pass multiple parameter from view to controller in .Net MVC

I need to pass 2 parameters id and date from view to controller side on the click event. It may be basic question but i am not able to do so.
I tried simply this code
Code <a href='/Abc/Details/id?=#website_id, date?=#date' class="" id="prev" >Prev</a>
and how to get those parameter at controller side.
I don't want to use "Ajax" or JavaScript if possible
First of all either you need to create custom route or enable MapMvcAttributeRoutes in your routeconfig file by adding below line of code.
routes.MapMvcAttributeRoutes();
Then in your controller above your defined action add something like below.
[Route("/Abc/Details/{id}/{date}")]
If you want to make it nullable then.
[Route("/Abc/Details/{id?}/{date?}")]
Your action method will be something like below.
[Route("/Abc/Details/{id?}/{date?}")]
public ActionResult Details(int id, string date)
Use #Html.ActionLink instead of hard coding your links.
If you wanted to go with custom route then add it above your default route.
routes.MapRoute(
"MyCustomRoute",
"Archive/{entrydate}",
new { Controller = "ABC", action = "Details",Id = UrlParameter.Optional,Date = UrlParameter.Optional});
Now in your view
#Html.RouteLink("Link Text", "MyCustomRoute", new { Id = YourId, Date=YourDate})
I found it easier to declare your variables in the Controller Action:
public IActionResult Create(string FirstName, string MiddleName, string
LastName, string ADUsername, string ADId, string ADName, string ADemail)
{
//do this
}
Then you can assign the variables by name in the View:
<a asp-controller="Employees" asp-action="Create" asp-route-
FirstName="#item.FirstName" asp-route-MiddleName="#item.MiddleName" asp-
route-LastName="#item.LastName" asp-route-ADUsername="#item.ADUsername" asp-
route-ADId="#item.ADId" asp-route-ADName="#item.ADName" asp-route-
ADemail="#item.ADemail">Add Employee</a>
I found #Mighty Ferengi answer very useful. Thanks man!
public IActionResult Create(string FirstName, string MiddleName, string
LastName, string ADUsername, string ADId, string ADName, string ADemail)
{
//do this
}
In Razor
<a asp-controller="Employees" asp-action="Create" asp-route-
FirstName="#item.FirstName" asp-route-MiddleName="#item.MiddleName" asp- route-LastName="#item.LastName"
asp-route ADUsername="#item.ADUsername"
asp-route-ADId="#item.ADId" asp-route ADName="#item.ADName"
asp-route- ADemail="#item.ADemail">Add Employee</a>

back button functionality in MVC application

I have a requirement to implement Back button functionality in MY MVC2 application(with explicit Back buttons in the application, not via browser back button).
I have gone through the link here Back button functionality using ASP.net MVC which advises to use Request.UrlReferrer. and it works well whenever I have a HTTP Get (as it comes up with querystring.) but I face issue when previous page was a HTTP POST with no querystring.
Has anyone worked on a solution like this?
We have initial thoughts of generating and storing links like Stack, and popping out urls one by one when user clicks on 'Back' button. But if there is a better solution\design pattern which helps me achieve that?
You could store the returnurl to actionresult routevalues and have a html helper for back link.
Helper:
public static class HtmlHelpersExtensions
{
public static MvcHtmlString BackLink(this HtmlHelper helper,string defaultAction)
{
string returnUrl = HttpContext.Current.Request["returnUrl"];
// If there's return url param redirect to there
if (!String.IsNullOrEmpty(returnUrl))
{
return new MvcHtmlString("<a href=" + returnUrl + " >Back</a>");
}
// if user just posted and there's no returnurl, redirect us to default
else if (HttpContext.Current.Request.HttpMethod == "POST")
{
return helper.ActionLink("Back", defaultAction);
}
// we didn't post anything so we can safely go back to previous url
return new MvcHtmlString("<a href=" + HttpContext.Current.Request.UrlReferrer.ToString() + " >Back</a>");
}
}
Controller:
public ActionResult MyAction(string returnUrl)
{
return View(new MyModel());
}
[HttpPost]
public ActionResult MyAction(MyModel mm, string returnUrl)
{
if (ModelState.IsValid)
{
// No returnurl, redirect us to somewhere
if (string.IsNullOrEmpty(returnUrl))
return RedirectToAction("Index");
// redirect back
return Redirect(returnUrl);
}
return View(mm);
}
Usage:
#Html.ActionLink("MyAction", "MyAction", new { returnUrl = Request.RawUrl.ToString() })
Backlink in MyAction.cshtml
#Html.BackLink("Index")
Now the helper decides whether it uses returnUrl param, default action or takes you back via urlreferrer.

MVC3 URL alternatives

After reviewing A LOT of questions and Internet data, I've solved a problem of mine with getting URL parameter from MVC3 application correctly.
Thing is that there wasn't a fault in coding, but in routing (I'm not so good with routing...).
Here's the current issue.
http://localhost:51561/Report/Details/1
This is the way my application presents Report details, which is good. But when it does it like this, I can't get value from URL parameter, like this
Request.QueryString["id"]
But, when I manually type in URL http://localhost:51561/Report/Details?id=1 it works...
Thing is i like the first URL type, but I don't know how to get parameter from it...
Help, please...
Update:
My Controller actions:
public ViewResult Details(int id)
{
Report report = db.Reports.Find(id);
ViewBag.TestID = Request.QueryString["id"].ToString();
return View(report);
}
public ActionResult Show(int id)
{
Report report = db.Reports.Find(id);
var imageData = report.Image;
return (File(imageData, "image/jpg"));
}
My View:
<div class="display-label">Picture</div>
<div class="display-field">
<img alt="image" src="<%=Url.Action("Show", "Report", new { id = ViewBag.TestID })%>" width="200px" />
</div>
First of all, you shouldn't use Request.QueryString in your application. Apart from that, in the first URL, you don't have a query string, and thus you can't access it (also read this article on msdn about Request.QueryString).
I also would like to suggest you to go through the basic tutorial of ASP.NET MVC3, to be found here. Many things like your question are thoroughly explained there.
To answer your question now, in your first URL example, the 1 in the URL is a parameter of your action (the Details action). You have to add this parameter to your method (action):
public ActionResult Details(int id)
UPDATE:
You have apparently the right action (method) declaration. Now, you can just use the parameter id. So change the Request.QueryString["id"] just by the variable (parameter) id.
public ViewResult Details(int id)
{
Report report = db.Reports.Find(id);
ViewBag.TestID = id;
return View(report);
}
There is no need to apply ToString() on the id, you shouldn't make it when it isn't necessary (you might need it somewhere else, later or so). Just put it in the ViewBag as the original type.
Your Show() method is good :). You have now the id parameter as you needed. (Try to avoid too many parentheses, it makes it look messy and now so clear.)
public ActionResult Show(int id)
{
Report report = db.Reports.Find(id);
var imageData = report.Image;
return File(imageData, "image/jpg");
}
You're not supposed to use Request.QueryString["id"] in MVC
Just add id parameter to your ReportController.Details action:
public ActionResult Details (int id)
The above is assuming you have a default route setup in Global.asax:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

ASP.NET MVC, Querystring, routes and default binder, how do I combine this?

I have an ASP.NET MVC site that uses strongly typed views. In my case, a controller action could look like this:
public ActionResult List(MyStrongType data)
When submitting the page (view) the response will generate a URL that looks something like this (yes, I know routing could generate a nicer URL):
http://localhost/Ad/List?F.ShowF=0&ALS.CP=30&ALS.L=0&ALS.OB=0&ALS.ST=0&S=&LS.L1=&LS.L2=&CS.C1=32&CS.C2=34&CS.C3=&ALS.ST=0
If I submit the page again, I can see that the data object in the action is set properly (according to the URL)(default binder).
The problem is: Say that I am to add page buttons (to change the page) for a list on my sitepage, the list will be controlled by settings like filter, sortorder, amount of pages per page and so on (controlled by the querystring). First, I need to include all current query parameters in the URL, and then I need to update the page parameter without tampering with the other query parameters. How can I genereate this URL from the view/"HTML helper"?
I could of course manipulate the URL string manually, but this will involve a lot of work and it will be hard to keep up to date if a route is changed, there must be a easier way? Like some kind of querystring collection that can be altered on service side (like ASP.NET Request.QueryString)?
I would hope to not involve the route, but I post the one I got so far anyway:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
"TreeEditing",
"{controller}/{action}/{name}/{id}",
new { controller = "MyCategory", action = "Add", name = string.Empty, id = -1 }
);
BestRegards
Edit 1: It's possible to set the query parameters like this (in view):
<%= url.Action(new {controller="search", action="result", query="Beverages", Page=2})%>
But this will only generate a URL like this (with the default route):
/search/result?query=Beverages&page=2
The rest of the parameters will be missing as you can see.
I could of course add every known parameter in this URL action, but if any query parameter is added or changed there will be a lot of work to keep everything up to date.
I have read the article ASP.NET MVC Framework (Part 2): URL Routing, but how do I find an answer to my problem?
It sounds to me like the problem you have is that you want to be able to easily persist query string values from the current request and render them into the URLs of links in your view. One solution would be to create an HtmlHelper method that returns the existing query string with some changes. I created an extension method for the HtmlHelper class that takes an object and merges its property names and values with the query string from the current request, and returns the modified querystring. It looks like this:
public static class StackOverflowExtensions
{
public static string UpdateCurrentQueryString(this HtmlHelper helper, object parameters)
{
var newQueryStringNameValueCollection = new NameValueCollection(HttpContext.Current.Request.QueryString);
foreach (var propertyInfo in parameters.GetType().GetProperties(BindingFlags.Public))
{
newQueryStringNameValueCollection[propertyInfo.Name] = propertyInfo.GetValue(parameters, null).ToString();
}
return ToQueryString(newQueryStringNameValueCollection);
}
private static string ToQueryString(NameValueCollection nvc)
{
return "?" + string.Join("&", Array.ConvertAll(nvc.AllKeys, key => string.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(nvc[key]))));
}
}
It will loop through the query string values from the current request and merge in the properties defined on the object you passed in. So your view code might look like this:
<a href='/SomeController/SomeAction<%=Html.GetCurrentQueryStringWithReplacements(new {page = "2", parameter2 = "someValue"})%>'>Some Link</a>
This is basically saying "keep the query string from the current request, but change the page and parameter2 values, or create them if they didn't exist." Note that if your current request has a "page" query string parameter, this method will overwrite the value from the current request with the one you explicitly pass in from the view.
In this case, if your querystring was:
?parameter1=abc&page=1
It would become:
?parameter1=abc&page=2&parameter2=someValue
EDIT:
The above implementation will probably not work with the dictionary lookup of querystring parameter names you described. Here is an implementation and that uses a dictionary instead of an object:
public static string UpdateCurrentQueryString(this HtmlHelper helper, Dictionary<string, string> newParameters)
{
var newQueryStringNameValueCollection = new NameValueCollection(HttpContext.Current.Request.QueryString);
foreach (var parameter in newParameters)
{
newQueryStringNameValueCollection[parameter.Key] = parameter.Value;
}
return ToQueryString(newQueryStringNameValueCollection);
}
Your view would call the function by doing an inline initialization of a dictionary and passing it to the helper function like this:
<a href='/SomeController/SomeAction<%=Html.GetCurrentQueryStringWithReplacements(new Dictionary<string,string>() {
{ QuerystringHandler.Instance.KnownQueryParameters[QuaryParameters.PageNr], "2" },
{ QuerystringHandler.Instance.KnownQueryParameters[QuaryParameters.AnotherParam], "1234" }})%>'>Some Link</a>
I did JUST what you need!
I created an HTML helper for this. The helper takes the same parameters as a normal helper. Yet, it keeps the current values from the URL. I made it both for the URL helper as a ActionLink helper.
This replaces the: Url.Action()
<a href='<%= Html.UrlwParams("TeamStart","Inschrijvingen", new {modID=item.Mod_ID}) %>' title="Selecteer">
<img src="<%= Url.Content("~/img/arrow_right.png") %>" alt="Selecteer" width="16" /></a>
and this replaces the Html.ActionLink()
<%: Html.ActionLinkwParams("Tekst of url", "Action", new {test="yes"}) %>
Here is the helper:
using System;
using System.Web.Mvc;
using System.Web.Routing;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Web.Mvc.Html;
namespace MVC2_NASTEST.Helpers {
public static class ActionLinkwParamsExtensions {
public static MvcHtmlString ActionLinkwParams(this HtmlHelper helper, string linktext, string action, string controller, object extraRVs, object htmlAttributes) {
NameValueCollection c = helper.ViewContext.RequestContext.HttpContext.Request.QueryString;
RouteValueDictionary r = new RouteValueDictionary();
foreach (string s in c.AllKeys) {
r.Add(s, c[s]);
}
RouteValueDictionary htmlAtts = new RouteValueDictionary(htmlAttributes);
RouteValueDictionary extra = new RouteValueDictionary(extraRVs);
RouteValueDictionary m = RouteValues.MergeRouteValues(r, extra);
//return System.Web.Mvc.Html.LinkExtensions.ActionLink(helper, linktext, action, controller, m, htmlAtts);
return helper.ActionLink(linktext, action, controller, m, htmlAtts);
}
public static MvcHtmlString ActionLinkwParams(this HtmlHelper helper, string linktext, string action) {
return ActionLinkwParams(helper, linktext, action, null, null, null);
}
public static MvcHtmlString ActionLinkwParams(this HtmlHelper helper, string linktext, string action, string controller) {
return ActionLinkwParams(helper, linktext, action, controller, null, null);
}
public static MvcHtmlString ActionLinkwParams(this HtmlHelper helper, string linktext, string action, object extraRVs) {
return ActionLinkwParams(helper, linktext, action, null, extraRVs, null);
}
public static MvcHtmlString ActionLinkwParams(this HtmlHelper helper, string linktext, string action, string controller, object extraRVs) {
return ActionLinkwParams(helper, linktext, action, controller, extraRVs, null);
}
public static MvcHtmlString ActionLinkwParams(this HtmlHelper helper, string linktext, string action, object extraRVs, object htmlAttributes) {
return ActionLinkwParams(helper, linktext, action, null, extraRVs, htmlAttributes);
}
}
public static class UrlwParamsExtensions {
public static string UrlwParams(this HtmlHelper helper, string action, string controller, object extraRVs) {
NameValueCollection c = helper.ViewContext.RequestContext.HttpContext.Request.QueryString;
RouteValueDictionary r = RouteValues.optionalParamters(c);
RouteValueDictionary extra = new RouteValueDictionary(extraRVs);
RouteValueDictionary m = RouteValues.MergeRouteValues(r, extra);
string s = UrlHelper.GenerateUrl("", action, controller, m, helper.RouteCollection, helper.ViewContext.RequestContext, false);
return s;
}
public static string UrlwParams(this HtmlHelper helper, string action) {
return UrlwParams(helper, action, null, null);
}
public static string UrlwParams(this HtmlHelper helper, string action, string controller) {
return UrlwParams(helper, action, controller, null);
}
public static string UrlwParams(this HtmlHelper helper, string action, object extraRVs) {
return UrlwParams(helper, action, null, extraRVs);
}
}
}
How does it work?
The calls are the same as for the Html.ActionLink() so you simple can replace those.
The method does the following:
It takes all the optional parameters from the current URL and places them in a RouteValueDictionary.
It also places the htmlattributes in a dictionary.
Then it takes the extra routevalues which you specified manually and places those in a RouteValueDictionary as well.
The key then is to merge the ones from the URL and the ones manually specified.
This happens in the RouteValues class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
using System.Collections.Specialized;
using System.Web.Mvc;
namespace MVC2_NASTEST {
public static class RouteValues {
public static RouteValueDictionary optionalParamters() {
return optionalParamters(HttpContext.Current.Request.QueryString);
}
public static RouteValueDictionary optionalParamters(NameValueCollection c) {
RouteValueDictionary r = new RouteValueDictionary();
foreach (string s in c.AllKeys) {
r.Add(s, c[s]);
}
return r;
}
public static RouteValueDictionary MergeRouteValues(this RouteValueDictionary original, RouteValueDictionary newVals) {
// Create a new dictionary containing implicit and auto-generated values
RouteValueDictionary merged = new RouteValueDictionary(original);
foreach (var f in newVals) {
if (merged.ContainsKey(f.Key)) {
merged[f.Key] = f.Value;
} else {
merged.Add(f.Key, f.Value);
}
}
return merged;
}
public static RouteValueDictionary MergeRouteValues(this RouteValueDictionary original, object newVals) {
return MergeRouteValues(original, new RouteValueDictionary(newVals));
}
}
}
This is all pretty straightforward. In the end, the actionlink is made with the merged routevalues. This code also lets you remove values from the URL.
Examples:
Your URL is localhost.com/controller/action?id=10&foo=bar. If in that page you place this code
<%: Html.ActionLinkwParams("Tekst of url", "Action", new {test="yes"}) %>
the URL returned in that element will be localhost.com/controller/action?id=10&foo=bar&test=yes.
If you want to remove an item, you just set the item as an empty string. For example,
<%: Html.ActionLinkwParams("Tekst of url", "Action", new {test="yes", foo=""}) %>
will return the URL in the <a> element: localhost.com/controller/action?id=10&test=yes
I'm guessing this is all you need?
If you have some additional questions, just ask.
Extra:
Sometimes you will want to keep your values inside your action too, when you will redirect to another Action. With my RouteValues class, this can be done very easily:
public ActionResult Action(string something, int? somethingelse) {
return RedirectToAction("index", routeValues.optionalParamters(Request.QueryString));
}
If you still want to add some optional parameters, no problem!
public ActionResult Action(string something, int? somethingelse) {
return RedirectToAction("index", routeValues.optionalParamters(Request.QueryString).MergeRouteValues(new{somethingelse=somethingelse}));
}
I think that covers pretty much everything you'll need.
If you want to set the query string in a link of a view:
Html.ActionLink("LinkName", "Action", "Controller", new { param1 = value1, param2 = value2 }, ...)
If you want to set it in the browser URL after a post back, just call Route* in an action like RouteToAction() and set the parameter key/value you want.
If you use the action public ActionResult List(MyStrongType data), you need to include all page settings (page index, ordering,...) as parameters to 'MyStrongType', and the data object will contain all infomation for the view.
In the view, if you need to generate a URL, using the approach of CallMeLaNN:
Html.ActionLink("LinkName", "Action", "Controller", new { param1 = Model.value1, param2 = Model.param2, ... });. You need to manually set all the parameters here or create a helper to help you fill the URL.
You don't need to care about current parameters included in the address.
You can route:
routes.MapRoute(
"custome",
"{controller}/{action}/",
new { controller = "Home", action = "Index"}
);
to generate all the parameters as a query string.

MVC AJAX action link not updating properly

I'm having a bit of trouble using AJAX action links. Whenever a link is clicked, the UpdateTargetID container is not updated unless the link is clicked twice (which throws an exception on the 2nd click, since the item has already been deleted; after this exception, the page updates).
Also, on the first update, the entire page is reloaded into itself, sort of like an iframe. I have a simple 3 column layout (header, left menu, right content) and the entire web page gets re-rendered in the right content portion. But only once. Subsequent action link clicks do not recursively render the page in itself.
I'm using the following code for an AJAX image link (found here: ASP.NET MVC Ajax.ActionLink with Image):
public static class ImageActionLinkHelper
{
public static string ImageActionLink(this AjaxHelper helper, string imageUrl, string altText, string actionName, object routeValues, AjaxOptions ajaxOptions)
{
var builder = new TagBuilder("img");
builder.MergeAttribute("src", imageUrl);
builder.MergeAttribute("alt", altText);
var link = helper.ActionLink("[replaceme]", actionName, routeValues, ajaxOptions);
return link.ToString().Replace("[replaceme]", builder.ToString(TagRenderMode.SelfClosing));
}
}
This is my action link in .aspx:
<%= Ajax.ImageActionLink("../../content/imgs/delete_icon.png", "Delete error", "Delete", new { id = new Guid(item.ErrorId.ToString()) }, new AjaxOptions { Confirm = "Delete?", UpdateTargetId="errors" }) %>
"errors" is my id to update
[HttpPost]
public ActionResult Delete(Guid id)
{
var error = db.ELMAH_Error.FirstOrDefault(x => x.ErrorId == id);
db.DeleteObject(error);
db.SaveChanges();
return PartialView();
}
You seem to be rendering the whole view. As a result invalid markup would be generated - duplicate body tags etc. Use partial views instead when dealing with Ajax scenarios.

Resources