URL-encode parameters in ActionLink? - asp.net-mvc

I have the following route registered;
routes.MapRoute(
"LocationsByArea",
"Locations/{system}/{storage}/{area}",
new { controller = "StorageLocation", action = "Index" },
null
);
...and the following code in my view;
<%= Html.ActionLink("Platser", "Index", "StorageLocation", new { system = Model.System, storage = Model.Storage, area = item.Name }, null)%>
My problem is when the "area = item.Name" contains a colon, e.g. "Area 4:1". If I click the rendered link I get HTTP-error 400, Bad reqest. I guess I have to encode my area parameter in some way, but I cant figure out how. Any help is apreciated.
Thanks!

The built-in encoding/decoding does not work, so I suggest you roll your own, like this:
namespace MyProject.Helpers
{
public static class JobNameHelper
{
public static string JobNameEncode(string jobname)
{
return jobname.Replace(":", "---colon---");
}
public static string JobNameDecode(string jobname)
{
return jobname.Replace("---colon---", ":");
}
}
}

Can you not just use
Server.UrlEnconde(item.Name)
Or am I missing something?
In your routing you may have to use Server.UrlDecde as well although I think It should decode for you on request.
Try using the Routing Debugger to see what the url router is getting passed, then you can see where the decoding needs to happen

ASP.NET 3.5 SP1 and earlier have a number of restrictions on which URLs are valid. In ASP.NET 4 most of these issues have been fixes (or are at least customizable via web.config). I think that the colon character, even when encoded, might not be allowed in ASP.NET 3.5 SP1 and earlier due to security concerns. Allowing colons can be a security problem when performing file checks since they are a little-known syntax for NTFS Alternate Data Streams.
I recommend trying to choose a character other than a colon for these purposes. Maybe a comma, semi-colon, or equal sign might work instead?

Related

Change Grails REST format /controller/<id>/<action>

I messed around with this a bit yesterday and failed miserably. I want to convert:
"/$controller/$action?/$id?"
To
#in psudo
"/$controller/$id?/$action?"
#ideal regex
"\/(\w+)(\/\d+)?(\/\w+)?"
The most obvious way failed "/$controller/$action?/$id?"
I can write the regex's to do it, but I am having trouble finding a way to using true regexs (I found RegexUrlMapping but could not find out how to use it), and also can't find documentation on how to assign a group to a variable.
My question is 2 parts:
How to I define a URL Resource with a true regex.
How to I bind a "group" to a variable. In other words if I define a regex, how do I bind it to a variable like $controller, $id, $action
I would also like to be able to support the .json notation /user/id.json
Other things I have tried, which I thought would work:
"/$controller$id?$action?"{
constraints {
controller(matches:/\w+/)
id(matches:/\/\d+/)
action(matches:/\/\w+/)
}
}
also tried:
"/$controller/$id?/$action?"{
constraints {
controller(matches:/\w+/)
id(matches:/\d+/)
action(matches:/\w+/)
}
}
The grails way to deal with this is to set
grails.mime.file.extensions = true
in Config.groovy. This will cause Grails to strip off the file extension before applying the URL mappings, but make it available for use by withFormat
def someAction() {
withFormat {
json {
render ([message:"hello"] as JSON)
}
xml {
render(contentType:'text/xml') {
//...
}
}
}
For this you'd just need a URL mapping of "$controller/$id?/$action?"
I'm not aware of any way to use regular expressions in the way you want in the URL mappings, but you could get a forward mapping working using the fact that you can specify closures for parameter values that get evaluated at runtime with access to the other params:
"$controller/$a?/$b?" {
action = { params.b ?: params.a }
id = { params.b ? params.a : null }
}
which says "if b is set then use that as the action and a as the id, otherwise use a as the action and set id to null". But this wouldn't give you a nice reverse mapping, i.e. createLink(controller:'foo', action:'bar', id:1) wouldn't generate anything sensible, you'd have to use createLink(controller:'foo', params:[a:1, b:'bar'])
Edit
A third possibility you could try is to combine the
"/$controller/$id/$action"{
constraints {
controller(matches:/\w+/)
id(matches:/\d+/)
action(matches:/\w+/)
}
}
mapping with a complementary
"/$controller/$action?"{
constraints {
controller(matches:/\w+/)
action(matches:/(?!\d+$)\w+/)
}
}
using negative lookahead to ensure the two mappings are disjoint.

Is there any way in Struts 2 by which I can get all namespaces in my app?

Is there any way in Struts2 by which I can get list of namespaces in my App ?
I want this as set or list at runtime .
I am using Struts2 RestActionMapper plugin.
When there invalid namespace is specified for valid action, Struts is throwing namespace error.
But I could not redirected to standard error page when this error occurs. I tried almost all options e.g.global error mapping default namespace etc . Nothing worked. So thought it would be great if I could get list of namespaces in my app, thus i could have checked invalid namespace against my list of valid namespaces and accordingly I could have thrown generic error which would finally result in my standard error page.
I am looking for how to get list of all namespaces in my project.
So basically I want to do something like this.
validNamespaces = getNamespaces();
if(validNamespaces.contains(namespaceRetrivedFromRestPlugin))
{Sysout("This is valid namespace.")}
else
{Sysout("Invalid namespace");}
This is possible, though like Steven has pretty much stated, I'm not convinced that this is the right approach to the problem you state of redirecting to an error page. But, I'll leave that part up to you and use this space to answer the namespace question.
This code will have to be in a Struts2-created object for the injection to work.
private Configuration configuration;
#Inject
public void setConfiguration(Configuration config) {
this.configuration = config;
}
protected Set<String> getNamespaces() {
Set<String> namespaces = Collections.emptySet();
Map<String, Map<String, ActionConfig>> allActionConfigs = this.configuration.getRuntimeConfiguration().getActionConfigs();
if (allActionConfigs != null) {
namespaces = allActionConfigs.keySet();
}
return namespaces;
}
The configuration can also be obtained from a ConfigurationManager. Also, you would obviously want to store these in a variable rather than calling above method over and over. If your object is, say, an interceptor, then you could call this method from the init() method and store it in a class-level variable.

T4MVC 2.6.65 and UseLowercaseRoutes=true error

Good day!
I'm using latest T4MVC from 2.6.65 from NuGet (upgraded from 2.6.64), I've set
// If true, use lower case tokens in routes for the area, controller and action names
static bool UseLowercaseRoutes = true;
And I got error:
The expression being assigned to '....' must be constant ...\T4MVC.cs
Here is the the generated code that triggers error:
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionNameConstants {
public const string Calc = ("Calc").ToLowerInvariant();
}
Is this a bug?
Ah sorry, the previous change broke it. I just pushed a new build of T4MVC (2.6.66) which addresses this. Well, it's more of a workaround as it basically doesn't generate the constant tokens when UseLowercaseRoutes is used. But that'll get us going for now.
The root of the problem is that C# doesn't support using .ToLowerInvariant() in constant strings. Ideally, it would just evaluate that at compile time, but it's not that smart :)

asp.net MVC: localization

I have my target language in Session["lang"], which is either "en" or "it". I have added this to the Site.master:
<script runat="server">
void Page_Load(object sender, EventArgs e) {
string lang = Session["lang"].ToString();
System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture(lang);
System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.CreateSpecificCulture(lang);
}
</script>
Then I'd like to invoke a resource string like this:
<asp:Label ID="Label1" runat="server" Text="<%$ Resources:Global, test %>"></asp:Label>
I have two files in the App_GlobalResources, named Global.resx and Global.en.resx.
The problems is that no matter what is in the lang variable, I always get the results from the main Global.resx, and I never get the english version from Global.en.resx
I am doing this wrong entirely??
I tried putting the System.Threading... part in the Application_PreRequestHandlerExecute method in Global.asax.cs but the result was the same.
Thanks
PS: I am asking about a way to make this work in a simple way. If I was to use the complicate way, I'd go with this: http://helios.ca/2009/05/27/aspnet-mvc-and-localization/
i had the same dilema(how to implement localization) in my asp.net mvc app.
I followed the instructions posted here and it works like a charm.
So i created a folder named Localization under Content and then i create Resources resx files for each language i want to translate. Keep in mind that there is a convention for the resx file names. ie
Resources.resx is the default fall back for everything.
Resources.en-GB.resx is for english GB
Resources.en-US.resx is for english US
etc.
Just make sure you follow the instructions posted in the link to embed and make the Resources available in all places in your app (views, controllers etc)
Edit:
I want to add that i ommited this line from web.config since i wanted to manually set the local from my app.
<globalization uiCulture="auto" culture="auto"/>
Instead i have created the following class:
public class SmartController : Controller
{
public SmartController()
{
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-US");
System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
}
}
All controllers inherit from this class.
Since this is an administrative set of the locale i have to set it from my apps settings. You could read it from Cookies and set it, or otherwise. This is imo the simplest solution for localization that i have encountered so far.
Once implemented you can refer to any string you add by the following simple line of code, no extra code needed.
<%= Resources.Strings.TranslatedTerm %>
I bet this one is a duplicate.
Anyway - all you need is here (assuming that you are using webforms viewengine (might work with others too, haven't investigated)).
Oh well... here goes my 'summary':
Helpers are just a part. You need to do some modifications with your default view engine too . On createview/createpartialview it should return localizationwebformview which adds a path key to viewdata which is used by htmlhelper to find resourceexpressionsfields and pass them to localizationhelpers class which retrieves desired value.
Little bonus=>
This might be handy if you don't want to recreate resource folders for view subfolders
(in case you modify viewengine.view/partialviewlocationformats):
private static string ReformatVirtualPath(string virtualPath)
{
//This allows NOT to duplicate App_localResources directory
// ~/Views/Shared/Partial/Some/BulltihS/_View.ascx
// turns into =>
// ~/Views/Shared/_View.ascx
var start = #"(~(/?\w*/?){2})";
var end = #"(\w*.as(c|p)x)";
start = Regex.Match(virtualPath, start).Value;
end = Regex.Match(virtualPath, end).Value;
return start + end;
}
usage:
internal static ResourceExpressionFields GetResourceFields
(string expression, string virtualPath)
{
virtualPath = ReformatVirtualPath(virtualPath);
var context = new ExpressionBuilderContext(virtualPath);
var builder = new ResourceExpressionBuilder();
return (ResourceExpressionFields)
builder.ParseExpression(expression, typeof(string), context);
}
EDIT:
but it might be a good idea to avoid App_GlobalResources and App_LocalResources as K. Scott Allen suggests (check Konstantinos answer).

ASP.NET MVC tests with MSpec. Is this correct or needs refactoring?

I'm new to MSpec and would like to know if the way I wrote my test for ASP.NET MVC is correct. The test passes but I don't really like the way it's written and it seems awkward. I'm certainly missing something.
public class AccountControllerTests3
{
protected static AccountController controller;
static IFormsAuthenticationService formsService;
static IMembershipService membershipService;
protected static ActionResult result;
protected static LogOnModel model;
Establish context = () =>
{
var controllerBuilder = new TestControllerBuilder();
formsService = MockRepository.GenerateStub<IFormsAuthenticationService>();
membershipService = MockRepository.GenerateStub<IMembershipService>();
model = MockRepository.GenerateStub<LogOnModel>();
controller =
controllerBuilder.CreateController<AccountController>(new object[]
{
formsService,
membershipService
});
};
Because user_logs = () =>
{
bool rememberMe = false;
membershipService.Stub(
x => x.ValidateUser("bdd", "mspec")).Return(true);
formsService.Stub(x => x.SignIn("bdd", rememberMe));
controller.ModelState.IsValid.ShouldBeTrue();
};
}
[Subject(typeof(AccountController), "LogInTests")]
public class When_logging_into_application_with_good_login_and_password : AccountControllerTests3
{
private It user_should_be_redirected_to_the_home_page = () =>
{
model.UserName = "bdd";
model.Password = "mspec";
result = controller.LogOn(model, string.Empty);
result.AssertActionRedirect().ToAction<HomeController>(
x => x.Index());
};
}
[Subject(typeof(AccountController), "LogInTests")]
public class When_logging_into_application_with_bad_login_and_password : AccountControllerTests3
{
It The_error_message_should_be_shown = () =>
{
model.UserName = "BAD";
model.Password = "BAD";
result = controller.LogOn(model, string.Empty);
controller.ModelState[""].Errors[0].ErrorMessage.ShouldEqual(
"The user name or password provided is incorrect.");
};
}
Thanks in advance,
Thomas
One of my goals when I write tests with MSpec is to get the "Assert" or the "It" down to one line. MSpec is not like NUnit in that it only executes the Context (made up of the Establish clauses from the current class and all base classes and the Because clause) once followed by all of the Specifications (It clauses).
This is designed explicitly to force you to not perform any behavior in the It clauses, but rather observe it.
What you're actually doing here is using MSpec like NUnit. Try and rewrite the tests in a single class (using no inheritance). Work backwards... in the It, place a single line that asserts what you want to assert. Perhaps the AssertRedirect. In the Because, try and put a single line that causes the observations to be observable. This would probably be your call to the controller's logon method. Finally, in the "Establish context" you'd want to put everything else.
After a while, you may want to pull some of the things in the Establish context only into a base class, but in doing so, be sure that your entire subclass stands alone in terms of understanding. A reader shouldn't need to read the base class in order to understand what the actual spec is doing. It's ok to hide ceremonial implementation details, but be sure to hide them behind descriptive method names.
There's another line I'm not sure about:
controller.ModelState.IsValid.ShouldBeTrue();
If this is a test, it should probably be in its own It clause. Though really, do you want to test this? What are you testing here? Shouldn't your controller take an action based on whether or not the model is valid? Shouldn't the result of that action be observable (validation error instead of login error). I just wonder if you really need to test this.
A few other things to check out, first for styling with R#, it seems your tests are falling victim to R#'s defaults. I posted about how to fight this here:
http://codebetter.com/blogs/aaron.jensen/archive/2008/10/19/getting-resharper-and-vs-to-play-nice-with-mspec.aspx
Also, James Broome has some nice MVC MSpec extensions that are worth checking out:
http://jamesbroo.me/introducing-machinespecificationsmvc/
Good luck and Enjoy! Feel free to ping me on twitter if you have any other unrelated questions.
Here's a remark: instead of using CreateController method use InitializeController, because it is compile-time safer and refactor friendlier.
Instead of:
controller = controllerBuilder.CreateController<AccountController>(
new object[] { formsService, membershipService });
Do:
controller = new AccountController(formsService, membershipService);
controllerBuilder.InitializeController(controller);
The first will still compile if you change the controller constructor arguments and it will blow at runtime, while the second will generate a compile-time error.

Resources