I've been searching for this for a while, and couldn't find anything, apologies if there is something and I've missed it.
Is there anything in the Web-API 2 framework that will automatically reject HTML tags on string model properties (except for a select few)?
I know I could create a custom validation attribute, and whack it on every property, but that's a lot of over head to maintain and remember to do on all new models.
public class Person {
public string Name{ get; set; }
// ... snipped
}
I can make a post request to my POST endpoint with JSON similar to:
{
"name": "<h1>This is my name</h1>"
}
In the action the person.Name will be equal to "<h1>This is my name</h1>", with no validation errors raised
I was looking for the same thing as you. Coming from a MVC standpoint where we have parameters to disallow html in input fields in forms, this seems reasonable.
I found this library tho, that sort of, in a way might help out... It does not fully answer your question in the way you want it, but it helps out with the custom attributes you would otherwise have to generate by yourself, if you decided to go for an attribute path...
Nuget package:
https://www.nuget.org/packages/ASPNetWebAPIAntiXss/
Examples and the product page:
https://bitbucket.org/embarr-development/asp.net-web-api-antixss-attribute
Related
.NET MVC Application EF code first, using Identity 2
Each application user belongs to a specific user_type (ApplicationUser.user_type). (the application uses Identity roles too, but they are completely independent of this user_type).
also, I am extensively using Display attribute on properties of models and viewmodels with:
[Display(Name="some literal"]
public string someProperty { get; set; }
and in the view:
#Html.LabelFor(model => model.someProperty)
or
#Html.DisplayNameFor(model => model.someProperty)
But now I am required to, in some cases, display different things if the logged-in user is of a specific user_type ("Client").
What would be the best way to implement this? I am guessing maybe its possible to customize the Display attribute so that it accepts a parameter "userType", so I could decorate the properties with something like:
[Display(Name="This will be shown to users with user_type: Client", UserType="Client"]
[Display(Name="This will be shown to everyone else"]
public int myProperty { get; set; }
or something like that... but I have no idea how to do it... any help is appreciated
To me it seems that you are trying to put too much logic/responsibility in one place.
I recon you would manage to come up with something to deal with this scenario, but, if you do, you'll risk ending up with an inter tangled property which behaviour will depend on all sorts of external parameters. The more you'll add, the more complex it will become. That can be hard to maintain.
I am not fond of "keep it simple" but I think it does apply here, by keeping it simple in maintenance.
IMO you have a couple of options to help you out:
create a complete new view and a model for this client page
add a propery to your (view)model which contains the string.
add the string to the page and handle it with razor.
use a viewbag or similar temp data container
So, to sum it: I dont think expanding the Display attribute would be the way to go here and consider one (or another) of the methods mentioned above.
I have already searched here to answer my question, and the closest I ever got was that post, but it still does not completely clarify the matter to me, so I will ask.
What I need is extending maxlengthattribute in the way that when I set it inside the C# file,
[MaxLength(50)]
[Display(Name = "Project Description")]
public string ProjectDescription { get; set; }
the attribute "maxlength" will be added inside the tag and will be <\stuff stuff maxlength = "50">
I have initially implemented it as writing html-helper to modify TextBoxFor, however, this is out of option since project is tightly intertwined with .js, and inserting renamed method will break a code, which will be a pain to fix.
The answer I referred above provides the closest explanation of what I need, but it looks like I will need to declare attributes (like inside ( ) in function), which I do not see there.
At this point I can either try modifying JS file on the server-side, or extending maxlengthattribute. Thus far, latter is preferable for me, thus I would like to ask how to properly extend it inside the c# file.
Thank you very much in advance!
You can write a custom dataannotation provider. The max length attribute will get added to the control.
Refer this link
One of the key features of a project I'm working on is the ability for the user to configure Forms (as in "Forms" to fill-up) based on a pool of pre-existing field types (well known types, for instance "user name", "date of birth" etc. but also "generic types" like "string", "DateTime" etc.).
We used to have a static ViewModel that worked fine for the "well known" types and looked like this:
public class UserInputModel
{
[StringLength(200)]
public string Name { get; set; }
[Required(ErrorMessageResourceName = "BirthDateEmptyError", ErrorMessageResourceType = typeof(Resources.ErrorMessages))]
public DateTime BirthDate { get; set; }
//Here comes a lot of other properties
}
All the known properties were listed and we were showing or hiding them given the context.
But the last requirement came and changed all that. The user shall now be able to add as many generic type fields as he wants. In order to do this, we decided to make this InputModel entirely dynamic. It now looks like this:
public class UserInputModel
{
// Each ModelProperty has an "Id" and a "Value" property
public ICollection<ModelProperty> Properties { get; set; }
}
This works like a charm. The razor view only has to iterates over the collection, create the corresponding controls for each property of the collection in a more than standard way:
#Html.TextBoxFor(m => m.Properties[index].Value);
... and we nicely get the data back as a filled form.
=> This works fine, but we don't have any client-side validation. For this, we would need some Metadata... which we don't have via annotations anymore since we're dynamically creating the model.
In order to provide those MetaData, I created a CustomModelMetadataProvider that inherits from DataAnnotationsModelMetadataProvider and registered it as the new ModelMetadataProvider in the Global.asax. The CreateMetadata() function gets called upon creation of the ViewModel, and that for each of the properties of my ViewModel... sofar so good.
Where the problem starts: in order to add some metadata to the current property, I first need to identify which property I am currently looking at ("Name" has a maxlength of 200, "date of birth" hasn't so I cannot assign a maxlength to every property per default). And somewhow I didn't manage to do that yet since all the properties have the same name Value and the same container type ModelProperty.
I tried accessing the container of the property via reflection, but since the ModelAccessor's target is the ViewModel itself (because of the lambda expression m => m.Properties), the following construct gives me the ViewModel as a whole, not just the ModelProperty:
var container = modelAccessor.Target.GetType().GetField("container");
var containerObject = (UserInputModel)container.GetValue(modelAccessor.Target);
I've been flipping this over and over but cannot find a way to identify which ModelProperty I have in hand. Is there a way to do this?
Update: after flipping this in every possible direction for a while, we finally went another way. We are basically using unobstrusive javascript to use MVC's validation capabilities without touching attributes nor metadata. In short, we add HTML attributes like value-data="true" (and all other required attributes) to the #Html.TextBoxFor() statements. This works wonderfully for all the atomic validations (required, stringlength etc.).
Tim, you can leverage what appears to be client-side validation through Ajax with the Remote attribute on your properties.
Basically, you'll need to set up a validation controller and then write some smarts into that controller. But at least you'd be able to write some helper methods and keep it all in one place. You would have a series of validators, based on the meta data that you are presenting to the end users, and each validator method would work for a particular type with good re-use.
The one pitfall to this approach would be that you would need to write a validation method for each type and condition that you want to support. Sounds like you're having to go down that road anyways, though.
Hope this helps.
See if this article help you: Technique for carrying metadata to View Models with AutoMapper.
Also use this one for ideas (custom model metadata provider): changing viewmodel's MetadataType attribute at runtime
Fluent validation is probably the best option for you in my mind, but its obviously up to you to select the best match among those above.
Update
Try use ModelMetadata and override ModelMetadataProvider: Dive Deep Into MVC: ModelMetadata and ModelMetadataProvider. This way you completely customize your model metadata (this replaces data annotations) and you have complete control on what is happening, rather than relying on ASP.NET MVC.
Another good place to look at it is Creating your own ModelMetadataProvider to handle custom attributes.
Hope this all is of help to you.
This is what the implementation would look like
public class Product
{
public integer id {get;set;}
[MultiLangual]
public string name {get;set;}
}
In the database, name would contain something like:
{en:Pataoto, nl: Aardappel, de: Patat, fr: pommes de terre}
This would contain all the translated fields, that a client has given to his own product.
(in this case: a patato).
In the frontend, this would appear as multiple html elements, which i (somehow) detect which language it is, on submitting the form.
My question is, how would i do this? I'm always stuck on creating the attribute and don't know where to continue...
In my attribute, i shouldn't do a lot, just something like this (i think):
public class MultiLangualAttribute : Attribute
{
public MultiLangualAttribute() : base()
{
}
public override string ToString()
{
return base.ToString();
}
}
But how would i detect everything in my views and create a custom layout for it (this should work with and .
It would only contain text.
Any ideas or a better implementation of above, would be VERY usefull :)
I think the better (arguably) implementation is standard way of application localization.
You define your resources and strings under App_GlobalResources folder you will have to create.
For example you will create file Fruits.resx with all your fruits you want to translate in your system language.
Afterwards you will create Fruits.de.resx, Fruits.es.resx etc, with all the languages you want to have in your website.
It is also possible to update the resources at runtime.
Its too much to describe all the approach in this answer, I would rather provide a link or two with detailed tutorial on MVC application localization:
This is classic ASP.NET MVC localization explanation:
Globalization And Localization With Razor Web Pages
Another explanation of the same thing, little more detailed is here:
ASP.NET MVC Localization: Generate resource files and localized views using custom templates
This should be enough for you to localize your app the standard way.
This is a little more advanced approach, when they use language as part of the URL you accessing.
es.yourdomain.com will be in Spanish, fr.yourdomain.com will be in French:
Localization in ASP.NET MVC – 3 Days Investigation, 1 Day Job
With regards to your approach (storing different languages in the database) here's link to microsoft approach for this. Its much more involved and complex, and I am not sure if benefitting you by its complexity, since you end up using database to fetch every single string in your app. Not the most efficient, but possible approach as well:
Extending the ASP.NET Resource-Provider Model
Hope this all will be of helps to you & good luck
I've been using T4MVC (FYI: v2.6.62) for quite some time, and I've been slowly moving over our code to this way of working (less reliance on magic strings).
But I've had to stop because, for some reason, T4MVC is unable to translate objects into urls, and only seems to be able to work on primitive types (int/string/etc).
Here is an example:
Route breakdown:
/MyController/MyAction/{Number}/{SomeText}
Class:
namespace MyNamespace
{
public class MyClass
{
public int Number { get; set; }
public string SomeText { get; set; }
}
}
Controller:
public class MyController
{
public virtual ActionResult MyAction(MyClass myClass)
{
return View();
}
}
View:
<%= Html.Action(
T4MVC.MyController.Actions.MyAction(
new MyClass()
{
Number = 1,
SomeText = "ABC"
}
) %>
The end result is this:
/MyController/MyAction?myClass=MyNamespace.MyClass
and not
/MyController/MyAction/1/ABC
Does anyone else have this problem? Are T4MVC urls like this available?
Question also asked at the ASP.NET Forum.
Update (10/11/2012): the recently added support for Model Unbinders (see section 3.1 in the doc) should hopefully cover a lot of these cases.
Original answer:
Copying my reply from the forum thread:
Hmmm, I don't think this has come up yet. Maybe in most cases that people have Action methods that take an object, the object's values come from posted form data, rather than being passed on the URL? In such scenario, the question doesn't arise.
I think in theory T4MVC could be changed to support this. It would just need to promote all the object's top level properties as route values rather than try to use the object itself (obviously, the current behavior is bogus, and is a result of just calling ToString() blindly).
Have others run into this and think it's worth addressing?
If I've understood the problem correctly then the following syntax should allow you to work around the problem.
<%= Html.ActionLink("test", MVC.MyController.MyAction().AddRouteValues(new MyClass() { Number = 5, SomeText = "Hello" })) %>
I think the answer to make the syntax nicer would be to wrap each non value type parameter in a RouteValueDictionary in each generated action result method
Edit: (Response to comment as not enough chars)
Ah ok I managed to recreate the simple example above using this method to give: /MyController/MyAction/5/Hello as the url.
I'm not quite sure how nested complex types would pan out in practice. You could use some recursion to dive down the into the top-level object and reflect over the values to add them but then you open up a new set of issues, such as how to cope with a child property name that is identical to the parent property name.
This seems like it could be a complex problem to solve, in a manner that would work for everyone.
Perhaps some kind of adapter pattern would be most useful to transform a complex object into route values. In the simplest case this might be to declare an extension method ToRouteDictionary that acts on your complex type and transforms it using your knowledge of how it should work. Just thinking out loud as I'm obviously not aware of your use cases