Is there a method for specifically hiding the routing parameters in ASP.NET MVC from the users. Specifically, I'd like a link
http://sitename.com/Do?title = 2
to simply become
http://sitename.com/Do
but internally pass the titleId to my controller.
Is that do able?
Thanks
Update: yes, there are buttons on my webpage that currently have such as their href, but I'd rather hide all the parameters so users dont go to other parts of the page directly by trying differnt parameters. #Moshe, no its not a from submit or post else I'd have used a strongly typed view. Thanks
As long as your parameters are on the client, they are never 'hidden' unless you encrypt them. You could store the parameter in a hidden field and set the action method to post, then the value is not visible in the URL. But a user with a little bit of knowlegde about web could still manipulate the hidden field (unless you encrypt the value in some way).
EDIT: If it has to be save you have to check the user's credentials on the server. Otherwise you can obscure the data like in the other sample or you can use encryption, e.g. with ProtectData.Protect(...).
For simple numeric values that have to be passed back and forth to a view you can write two private methods in your controller:
private int Obscure(int source) {
return (source*source) * 3; //or something clever you come up with
}
private int DeObscure(int obscuredValue) {
return (int)Math.Sqrt(obscuredValue / 3); //inverse the Obscure method
}
You can use these to obscure values before you pass them to a view, and de-obscure them after you get them posted back. Mind you, this is really not a good way to implement security, as is explained in this stackoverflow post.
Another option is to create an Obscure/DeObscure procedure that takes in the entire querystring and somehow mangles that back and forth. This would required writing a custom ViewEngine though. Sounds interesting...
Related
Spring MVC 4.1
Hi,
I have a situation where, on a single page, there are several input fields. As the users enters numbers into these fields, a bunch of calculations will occur and update various other fields on the page.
I want this whole calculation model to take place in Java on the server-side. I really want to avoid replicating this logic in Javascript on the client.
What I envision is...
User opens the page, the object that does the calculations (let's call it Calculator) is created and its initial state is set (many of its fields are pre-populated with values).
This Calculator instance is stored and available for the duration of the user's time on that page.
Whenever the user changes a value in an input field, that new value is sent to the server via ajax and plugged into our Calculator object. The Calculator, re-calculates the other fields based on the new state and returns the results to the page.
The other fields on the page are updated accordingly.
The key here is that I'm not sending the state of all fields with each ajax request. I'm only sending the current value that was updated. Essentially, I'm trying to ensure that the form state and the Calculator state on the back-end are always synchronized.
I have looked into #SessionAttributes and #ModelAttribute.
The problem with #ModelAttribute, as I understand it, is that it will be re-created with each ajax request.
The problem with #SessionAttributes is that it is a session variable. What if the user has two of these windows open? And how do I ensure the object is removed from the session when they leave the page? etc...
Maybe there's no magic Spring bullet and I just have to figure out the session variable thing. But any pointers on dealing with this would be much appreciated.
Thanks!
You have a couple of options:
.1. Like you have said using the #SessionAttributes, however yes it suffers from the issue that you have mentioned, multiple instances of the same session will see the same variable.
.2. Store state somewhere else and re-hydrate the state using #ModelAttribute annotated method. I would personally prefer this approach, essentially when you create the form, create it with a identifier for the current state:
#RequestMapping(params = "form")
public String createForm(Model uiModel) {
uiModel.addAttribute("calculationId", UUID.randomUUID().toString());
return "calculationpage/create";
}
Then for subsequent ajax requests, ensure your previous calculationId is sent across:
#ModelAttribute("calculationState")
public CalculationState rehydrateState(String calculationId) {
//retrieve current state of calculation from some persistent store..
}
#RequestMapping("/calculate")
public String handleCalculation(#ModelAttribute("calculationState") CalculationState c) {
//you will get a calculationstate with the delta's at this point..
}
.3. Another potential approach may be to use session but disambiguate different instances within the session with a custom id:
public String handleCalculation(HttpSession session, #RequestParam("calcId") String calcId) {
CalculationState calcState = (CalculationState) session.getAttribute("calculation" + calcId);
}
You need any sort of persistent store outside session to store and retrieve the state of your calculator model. Like Biju said, I will go for solutions like No 2.
I am creating a TextBox using the html helper methods in my View.
#Html.TextBoxFor(m => m.Address, new { #readonly = "readonly" })
I would like this textbox to retain its value when posted, even if a malicious user tries to change it.
I am testing my code in IE, and can easily use the developer tools to remove the attribute "readonly".
Is there any implementation in MVC3 to retain values for the textboxes when posting? I am trying to avoid going to the database to get the original value.
Is there any implementation in MVC3 to retain values for the textboxes when posting?
No, there isn't. This is not possible. If you have sent the value up to the client you can no longer trust it. As you have already discovered it is trivial for the user to change the value of hidden and readonly fields. So if those values aren't meant to be modified by the user they should not even be part of the HTML. You should keep them on the server. Well, actually you could display them as readonly fields just for information to the user but when the form is submitted never use this value but use the real value that is stored on your server (maybe in a database or whatever persistent store you are using).
Why not try serializing everything you want to retain, encrypt it using a key only known to the server and store the encrypted value into a hidden input. You can still display the non-encrypted values in the form controllers, but at the server side, you will use the encrypted value send via the hidden input for actual processing. This way if a malicious user changes the standard inputs, it doesn’t matter, coz you will be using the encrypted copy.. A bit of a sidewinder, I know and its similar to how web forms maintains viewstate across posts.. Cheers
I suspect I'm doing this wrong.
For various reasons, my app forces the user to make some choices right after login. In order to ensure that they enter the necessary data, I override the OnActionExecuting method in a base controller class to intercept any attempt at executing an action before this data has been entered, and redirect the user to the necessary page. I preserve the url of the action they were attempting to execute with the following code:
url = Url.RouteUrl("Default", filterContext.RouteData.Values);
(filterContext is an ActionExecutingContext object, and a parameter of OnActionExecuting.)
The problem I'm having is that, if the action was associated with a controller in an area, the url I get doesn't reflect the area.
I understand from other posts that I can get the area name from the DataTokens collection of RouteData. But I'm uncertain of the best way to pass it. I suppose I could retrieve it and use the RouteValueDictionary.Add method to add it to RouteData.Values (assuming Values is not read-only at that point; I don't know), but that feels a bit ... odd, like somehow the point is being missed.
Is this really the way this is supposed to be done? Is there something wrong elsewhere, that Area is absent from my RouteData.Values?
I would just take it out of the data tokens in the filter and add it to route values. You can do it with RouteValues.Add:
if (filterContext.RouteData.DataTokens.ContainsKey("area"))
filterContext.RouteData.Values.Add("area",
filterContext.RouteData.DataTokens["area"]);
The areas feature was added in MVC2, and I imagine this is a side effect of it not being in MVC1. However, as long as your RouteValues contains an "area" key, UrlHelper.RouteUrl should generate the correct URL for the area.
I have a GET action for creating records. Because the page is somewhat dynamic, I don't use a model to hold the data. I go off to do some OAuth, only to return to the create screen later on. In order to pass the data back, I am redirecting with a query string. I parse the query string in the GET action, and then show the view. The thing is, the query string is showing up in the browser. This displays pseudo-sensitive data.
Since I am only using the query string for transferring data, I am wondering if I can throw the query string away to prevent it from showing up on the browser.
Otherwise, is there a way to go to another action without redirecting? I've found, if I call the "other" action method directly, it tries to find the view of the original action. I can explicitly change the return View(viewModel) line to return View("create", viewModel) but that seems really dirty.
You should consider changing the action to accept POST requests. At least this will prevent the sensitive information from appearing in the browser. For extra security, your site should be served via SSL.
The other thing you can try is encrypting the sensitive values or the entire query string. The only problem is that this, too, will be preserved in the browser's history unless you require users to log in.
It looks like your action method is trying to do too much. Authentication/authorization is a separate concern which should not be part of the action method. It is better to move the authentication work in to an action filter.
Create an class that extends authorization attribute and override its OnAuthorization method to do your authorization work.
This frees your controller action method to accept POST requests.
I switched from Intelligencia's UrlRewriter to the new web forms routing in ASP.NET 4.0. I have it working great for basic pages, however, in my e-commerce site, when browsing category pages, I previously used querystrings that were built into my pager control to control paging and now am not sure how to handle this using routing.
I defined a MapPageRoute as:
routes.MapPageRoute("cat-browse", "Category/{name}_{id}", ~/CategoryPage.aspx");
This works great. Now, somebody clicks to go to page 2. Previously I would have just tacked on ?page=2 to the url. How do I handle this using web forms routing? I know I can do something like:
http://www.mysite.com/Category/Arts-and-Crafts_17/page/2
But in addition to page, I can have filters, age ranges, gender, etc.
Should I just keep defining routes
that handle these variables like
above?
Should I continue using querystrings
and if so, how do you define a route
to handle that?
The main reason to use url routing is to expose clean, user-and-SEO-friendly, URLs. If this is your goal, then try to stick to it and not use querystring parameters. Note: I don't believe we need to completely ban the use of querystrings and, depending on your situation, you may decide it best to use querystring parameters for parameters that are not used frequently, or where no real value is added by making the information more semantically meaningful.
So here's what I would do:
Define a catch-all for all your other parameters:
routes.MapPageRoute("cat-browse", "Category/{name}_{id}/{*queryvalues}", "~/CategoryPage.aspx");
In /CategoryPage.aspx, access the router parameter and then parse as appropriate:
Page.RouteData.Values["queryvalues"]
Instead of using the syntax of Arts-and-Crafts_17/**page/2/age/34** for these parameters, I perfer to use the following syntax: Arts-and-Crafts_17/pg-2/age-34/
If you do this, the catch-all parameter 'querystring', will equal pg-2/age-34. You can now easily parse this data and add each name/value to the page context. Note that you will need to do something along these lines since each of these parameters are optional on your site.
You can take advantage of C# 4.0 named and optional parameters. Please have a look at this example from haacked
If you are using a lower version of the framework, you can also use code from the link above. But instead of declaring the method as
public ActionResult Search(int? page=0)
{}
you can declare it as
public ActionResult Search(int? page)
{
if(page == null)
{
page=0;
}
}
HTH