I use MVC 4 and have moved some logic into an authorize filter. I am trying redirect to an error page based on not being authorized. I would like to set the last page route and a few other properties to catch the error.
Below is my override
// handle unauthorized
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Controller.ViewBag.LastRoute = filterContext.RouteData;
filterContext.Controller.ViewBag.Issue = "put...val here";
var routeValues = new RouteValueDictionary(new
{
controller = "Error",
action = "Oops"
});
filterContext.Result = new RedirectToRouteResult(routeValues);
}
controller
[AllowAnonymous]
public ActionResult Oops()
{
var m = new Core.Models.ErrorModel();
var v = ViewBag.Issue; // == null
return View("~/Views/Error/Oops.cshtml", m);
}
I tried how to set values to viewbag in actionfilterattribute asp mvc 5 for action filters and it works
Any help would be appreciated.
EDIT:
Sorry when I get to the controller the value for:
ViewBag.Issue = null.
I'm not sure how to set the property and have it hold value.
RedirectToRouteResult is going to send a redirect response to the browser and browser will issue a brand new GET request to the url specified. ViewBag data do not survive between 2 http requests.
You may use TempData which will keep the data between 2 seperate http requests. You can set your TempData value in one action method and any action method that is called after this can get values from the TempData object and then use it. TempData use Session behind the scene to store data. The value of TempData persists until it is read or until the session times out. This is ideal for scenarios such as redirection because the values in TempData are available beyond a single request.
So in your action filter you can set the TempData dictionary instead of ViewBag.
filterContext.Controller.TempData["Issue"] = "Robots are laughing non stop";
var routeValues = new RouteValueDictionary(new
{
controller = "Home",
action = "Oops"
});
filterContext.Result = new RedirectToRouteResult(routeValues);
Now in your Oops action method, you may read the TempData value you set
public ActionResult Oops()
{
var issueDetails = TempData["Issue"];
// TO DO : Do something useful with issueDetails :)
return View();
}
Keep in mind that TempData values won't be available after you read it. So if you want to read it in your view again, set it again or better use a view model and set the already read value as the property value of your view model.
Related
I am learning ASP.net MVC5 with the code in book.
public ActionResult DemoTempData()
{
ViewData["Msg1"] = "From ViewData Message.";
ViewBag.Msg2 = "From ViewBag Message.";
TempData["Msg3"] = "From TempData Message.";
return RedirectToAction("Redirect1");
}
public ActionResult Redirect1()
{
TempData["Msg4"] = TempData["Msg3"];
return RedirectToAction("GetRedirectData");
}
public ActionResult GetRedirectData()
{
return View();
}
GetRedirectData view:
#{
ViewBag.Title = "GetRedirectData";
}
<h2>GetRedirectData</h2>
<ul>
<li>ViewData-Msg1:#ViewData["Msg1"]</li>
<li>ViewBag-Msg2:#ViewBag.Msg2</li>
<li>TempData-Msg3:#TempData["Msg3"]</li>
<li>TempData-Msg4:#TempData["Msg4"]</li>
</ul>
I know that ViewData and ViewBag will not pass value.
The Msg3 and Msg4 in view should have value, but it doesn't.
I check the value in Redirect1(), it turns out that Msg3 is null.
I am very confused with what's going on.
ASP.NET MVC TempData stores it’s content in Session state. So TempData gets destroyed immediately after it’s used in subsequent HTTP request.
In your case you are assigning the TempData["Msg3"] to TempData["Msg4"]. So once you consume the content from TempData["Msg3"] it gets destroyed. So whenever you try to access TempData["Msg3"] you get null value.
The Peek and Keep methods allow you to read the value without getting destroyed.
reference :
https://msdn.microsoft.com/enus/library/system.web.mvc.tempdatadictionary.peek(v=vs.118).aspx
object value = TempData["value"];
TempData.Keep("value");
object value = TempData["value"];
in the controller Use the builtin Session plumbing, it stays with you until you destroy it. I like it because it always works, and its easy. It is available in
System.Web.HttpContext
which is really the current request
to save use (Example)
System.Web.HttpContext.Current.Session["Msg3"] = StringOfIds;
To retrieve...
string msg3= (string) System.Web.HttpContext.Current.Session["Msg3"];
Basically I am learning about difference between ViewBag, ViewData, TempData in practical.I am in confusion with the theory of these concepts so I want to see how things happen in practical.
I learned that TempData is used to send data from controller to controller i.e from one action method to another action method, and it is short lived.Even then I can pass TempData value to a View as well. As I read that it's value gets null after subsequent request. But In my sample code snippet though there exist a value in TempData after a redirection, I'm unable to assign it to a variable.
public ActionResult Index()
{
var featuredProduct = new Product
{
Name = "Special cupcakes",
Des = "Delectable vanilla and chocolate cupcakes",
Creationdate= DateTime.Now,
Expirydate= DateTime.Today.AddDays(7)
};
ViewData["FeaturedProduct"] = featuredProduct;
ViewBag.product = featuredProduct;
TempData["FeaturedProduct"] = featuredProduct;
return Redirect("~/Home/Show");
}
As this is the first redirection i.e next subsequent request after setting TempData, the value should persist in TempData of Show Action method.
public ActionResult Show()
{
var testdata= ViewData["FeaturedProduct"];
var testbag = ViewBag.product;
var tempdata = TempData["FeaturedProduct"];
return View();
}
Now my confusion is around here. If I want to access TempData in the Show View, I expect that it should be null. When I see in Quick Watch,it's value persisted and it's value is not getting assigned to the variable.So What exactly is happening with TempData.
#{
var tevar = TempData["Featured Product"] as Product;
}
#{
if (TempData["Featured Product"]!=null)
{
<b><u>
#tevar.Name
</u></b>
}
else{
<b> Sorry tempdata values perished</b>
}
}
Though this appear very basic please bear with me and explain me what happening with TempData in my code.
Thank You.
You've got a typo in your Show view:
#{
var tevar = TempData["Featured Product"] as Product;
}
should of course be:
#{
var tevar = TempData["FeaturedProduct"] as Product;
}
Make sure that you access the value using the same key as you stored it with.
I could now clearly comprehend the difference between ViewBag, ViewData, TempData.
ViewBag and ViewData value will be lost after redirection, but TempData value will remain between the redirection until a refresh of the current action method occurs or if we navigate to other action method.
I have an ActionFilter that is successfully capturing page views along with important information from the request. The primary key of this captured entry is then associated with an activity (i.e: Successful Login).
I am trying to now automatically capture Redirects (i.e: RedirectToAction) and associate this with the page view as well. I believe this can be done in my ActionFilter that is capturing page views, but I am unsure if there is a way to tell from the OnActionExecuting context whether or not the GET request is coming from a redirect.
Is there a way to tell from an HttpRequest / ActionExecutingContext(or ActionExecutedContext) whether or not the page is coming from a redirect?
Thanks!
RedirectToAction returns a RedirectToRouteResult
In the OnActionExecuted method of your filter -
if (filterContext.Result is RedirectResult)
{
// It was a RedirectResult
var result = filterContext.Result as RedirectResult;
var url = UrlHelper.GenerateContentUrl(result.Url, filterContext.HttpContext);
}
else if (filterContext.Result is RedirectToRouteResult)
{
// It was a RedirectToRouteResult
var result = filterContext.Result as RedirectToRouteResult;
var url = UrlHelper.GenerateUrl(result.RouteName, null, null, result.RouteValues, RouteTable.Routes, filterContext.RequestContext, false);
}
When a view has been rendered in memory and before it is sent as a response to the client, I would like to intercept the call, check which view is being rendered, what was the action and controller, and do some house-keeping.
Therefore, I am implementing a ResultFilter and overriding the OnResultExecuted method.
Within this method, how do I get the route data to figure out which view, action, controller were called?
Update
My profuse apologies. I just looked up ResultExecutedContext in reflector and it showed me only an Exception, Cancelled and ActionResult property. It didn't show me any RouteData. When I fired up the IDE, it did show me the route data. I feel like a dick for asking this question.
You could get it from the filterContext's RouteData property:
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
RouteData rd = filterContext.RouteData;
// read from the current request RouteData the information
// you were looking for. For example to get the current controller
// and action:
string currentController = rd.GetRequiredString("controller");
string currentAction = rd.GetRequiredString("action");
}
As far as which view was rendered is concerned you could retrieve this information from the Result property:
var viewResult = filterContext.Result as ViewResultBase;
if (viewResult != null)
{
// the controller action returned a view result (either a ViewResult or PartialViewResult)
// so we could retrieve the view name here:
string viewName = viewResult.ViewName;
}
If on the other hand the controller action returned a JsonResult you could also extract retrieve it:
var jsonResult = filterContext.Result as JsonResult;
and so on...
ResultExecutedContext has a RouteData property which should give you what you need
I have this api controller action that takes an object "ContentList" as parameter.
[HttpPost]
public List<string> SendList(string param, ContentList list)
{
List<string> testReturn = new List<string> { "test1", "test2", "test3", "test4" };
return testReturn ;
}
What I have tried so far is to call a controller action like this:
Uri _uri = new Uri("http://localhost:xxxxx/api/FakeTest/SendList?param=test");
var serializer = new JavaScriptSerializer();
string requestData = serializer.Serialize(new
{
list = ContentList,
});
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/json";
var result = client.UploadData(_uri, Encoding.UTF8.GetBytes(requestData));
var tempString = Encoding.UTF8.GetString(result);
}
In this example, tempString = ["test1","test2","test3","test4"] as reurned by the controller action..
In the controller action, I can access the properties of the passed in ContentList, and return their values (changing the actions return value accordingly ofcourse).
However, in the controller action, I need to send off the ContentList object for further processing, and this seems to fail. I get a 500 internal server error, and I can't put a breakpoint in the controller to follow the values passed in. The debugger never hits it...
I expect this has something to do with sending json to the controller action.
Anyway, it seems that the ContentList is rejected by the code it is sent to from the controller action, so I figure I need to do some sort of de-serializing, right?
Bottomline, the question is, what is the correct way to call a controller action from code, pass in a C# object, and make it usable from the controller action?
If you are using MVC 3 your controller should be able to reveive and parse json data in a direct way. If you are using MVC 2 you'll need to register a new factory on your application to take care of json parsing on the controller
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
}
More info on the subject here:
http://haacked.com/archive/2010/04/15/sending-json-to-an-asp-net-mvc-action-method-argument.aspx