This might be more of a question related to how .NET Framework works, than looking for an actual solution. Reason is I would like to know if this is something I should pursue in fixing, or try something else entirely. I did some searching, but couldn't find the right answer in my opinion.
I am working on an ASP.NET MVC5 application that utilizes a translation provider with an XML file as it source. In some scenarios I use a DisplayNameAttribute extension to decorate model properties to provide translations. It is made by referencing the solution here: https://stackoverflow.com/a/9723620/1501132
This is my implementation:
[AttributeUsage(AttributeTargets.Property)]
public sealed class LocalizedDisplayNameAttribute : DisplayNameAttribute
{
public LocalizedDisplayNameAttribute(string key, string page = null) : base(FormatMessage(key, page))
{
}
private static string FormatMessage(string key, string page = null)
{
if (!string.IsNullOrWhiteSpace(key) && string.IsNullOrWhiteSpace(page))
{
return TextGetter.GetText(key);
}
else if (!string.IsNullOrWhiteSpace(key) && !string.IsNullOrWhiteSpace(page))
{
return TextGetter.GetText(key, page);
}
else
{
return string.Empty;
}
}
}
The "TextGetter" is a separate library that handles fetching strings from the XML data source.
The attribute extension is used like so:
[LocalizedDisplayName("Timestamp", "/report")]
public DateTimeOffset Timestamp { get; set; }
The website also has a feature where a super user can edit the translation XML file, in case some translations are wrong or missing. Usually an edit in the XML file is visible immediately, except for properties with this particular attribute. I know that normally when using DisplayName attribute with a hardcoded value can not be changed because it is compiled, though I was under the assumption that since this uses an XML file as reference, I believed that if the XML was changed it would be reflected immediately in this case as well. But that seems not to happen.
Being able to change translations on the fly is an important feature; should I seek some other solution? I can set the property names with translations in the views, which is working, but that will entail a LOT of refactoring, and keeping it as annotations is just more neat.
I don't really know where to take it from here.
Found a solution in the meantime, and just putting it out there if anyone stumbles across it. So this is what you should do, if you want to make an attribute that derives from DisplayName used for localization, and on top of that have a localization source that can change and update during runtime:
[AttributeUsage(AttributeTargets.Property)]
public sealed class LocalizedDisplayNameAttribute : DisplayNameAttribute
{
private readonly string _key;
private readonly string _page;
public LocalizedDisplayNameAttribute(string key, string page = null) : base(key)
{
this._key = key;
this._page = page;
}
public override string DisplayName => this.FormatMessage(this._key, this._page);
private string FormatMessage(string key, string page = null)
{
if (!string.IsNullOrWhiteSpace(key) && string.IsNullOrWhiteSpace(page))
{
return TextGetter.GetText(key);
}
else if (!string.IsNullOrWhiteSpace(key) && !string.IsNullOrWhiteSpace(page))
{
return TextGetter.GetText(key, page);
}
else
{
return string.Empty;
}
}
}
The contents of "FormatMessage" can be whatever you want really, just insert there whatever code you need to fetch your translated string.
I am writing a proxy to wrap a WCF service with ASP.net Core and this is my first time using ASP.Net core.
I am using an auto-generated WCF service contract, and the issue is my WCF service changes frequently, so I must update/refresh the WCF service, and whenever I update my contract, I lose my minor tweaks.
I'm only trying to:
Hide some properties - via changing public string Property to internal string Property. I've tried [IgnoreDataMember] and [JsonIgnore] but those don't seem to work
Make some properties required - via RequiredAttribute
Default some property values - via DefaultValueAttribute
I've tried two approaches so far but they're not working fully.
This represents the automatically generated WCF Contract where I want to require & default MyProperty1 and hide MyProperty2:
// This is the automatically generated WCF Contract
public partial class MyClass
{
private string myPropertyField1;
private string myPropertyField2;
public string MyProperty1
{
get { return this.myPropertyField1; }
set { this.myPropertyField1 = value; }
}
public string MyProperty2
{
get { return this.myPropertyField2; }
set { this.myPropertyField2 = value; }
}
}
Method 1:
ModelMetadataType to override the contract metdata. This partially works, but not for all attributes for some reason? It feels like a bug.
[ModelMetadataType(typeof(MyClassMetadata))]
public partial class MyClass { }
public partial class MyClassMetadata
{
[Required] // This does not work
[DefaultValue("SomeValue")] // This DOES work?
public string MyProperty1 { get; set; } // I want this required & defaulted
[IgnoreDataMember] // This does not work to hide
[JsonIgnore] // This does not work to hide
public string MyProperty2 { get; set; } // I want this hidden from Swagger view
}
Which works to default values, but it doesn't appear to make it required or hidden?
Method 2:
I tried creating derived class, and then using the derived class instead of MyClass for the controller api arguments, but then when I try to call it I receive an error that says something like Type MyClassDerived was not expected. Use XmlInclude to specify unexpected types...
public partial class MyClassDerived : MyClass
{
[Required] // This puts "*" next to it in Swagger
[DefaultValue("SomeValue")] // This defaults the value in Swagger
public new string MyProperty1
{
get { return base.MyProperty1; }
set { base.MyProperty1 = value; }
}
internal new string MyProperty2 // This works to hide from Swagger
{
get { return base.MyProperty2; }
set { base.MyProperty2 = value; }
}
}
How can I hide/default/require contract properties without directly modifying an auto-generated WCF contract service class?
I am developing a wcf web service. It was working correctly during unit testing. A few days back, I changed the default namespace from 'tempuri' as explained in this link: http://blog.rebuildall.net/2010/11/10/wcf_service_namespaces and also added 'Order' Property to the datamembers i.e. like [DataMember(Order = 1)] of both request and response classes. Now in one OperationContract, some parameters are being read as null at server side even though value is passed at client side. I also noticed that the responses of a couple of OperationContracts were showing empty tags when there should have been value in those tags.
On searching, I found blog with a similar problem, but what caused their problem was a name mismatch of a parameter in client and server side. The link to the blog is : http://blog.functionalfun.net/2009/09/if-your-wcf-service-is-unexpectedly.html
Can anyone guide me here. Thanks in advance
I dunno if anyone else manages to get this error the way I did, but this was the problem:
I had defined my classes like below:
public class CompositeType
{
private bool boolValue;
private string stringValue = "";
[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}
By removing those variable declarations and using auto-property syntax, I was able to get past the issue. i.e like :
public class CompositeType
{
[DataMember]
public bool BoolValue
{
get;
set;
}
[DataMember]
public string StringValue
{
get;
set;
}
}
We have an application with three layers: UI, Business, and Data. The data layer houses Entity Framework v4 and auto-generates our entity objects. I have created a buddy class for the entity VendorInfo:
namespace Company.DataAccess
{
[MetadataType(typeof(VendorInfoMetadata))]
public partial class VendorInfo
{
}
public class VendorInfoMetadata
{
[Required]
public string Title;
[Required]
public string Link;
[Required]
public string LinkText;
[Required]
public string Description;
}
}
I want this validation to bubble up to the UI, including custom validation messages assigned to them. In MVC this is a piece of cake but in web forms I have no clue where to begin. What is the best way to utilize model validation in asp.net web forms?
I did find an article that explains how to build a server control for it, but I can't seem to get it working. It compiles and even recognizes the control but I can never get it to fire.
Any ideas?
Thanks everyone.
I solved it. It would appear that the server control I found was not designed to read fields in a buddy class via the MetadataType attribute. I modified the code to look for its validation attributes in the buddy class rather than the entity class itself.
Here is the modified version of the linked server control:
[DefaultProperty("Text")]
[ToolboxData("<{0}:DataAnnotationValidator runat=server></{0}:DataAnnotationValidator>")]
public class DataAnnotationValidator : BaseValidator
{
#region Properties
/// <summary>
/// The type of the source to check
/// </summary>
public string SourceTypeName { get; set; }
/// <summary>
/// The property that is annotated
/// </summary>
public string PropertyName { get; set; }
#endregion
#region Methods
protected override bool EvaluateIsValid()
{
// get the type that we are going to validate
Type source = GetValidatedType();
// get the property to validate
FieldInfo property = GetValidatedProperty(source);
// get the control validation value
string value = GetControlValidationValue(ControlToValidate);
foreach (var attribute in property.GetCustomAttributes(
typeof(ValidationAttribute), true)
.OfType<ValidationAttribute>())
{
if (!attribute.IsValid(value))
{
ErrorMessage = attribute.ErrorMessage;
return false;
}
}
return true;
}
private Type GetValidatedType()
{
if (string.IsNullOrEmpty(SourceTypeName))
{
throw new InvalidOperationException(
"Null SourceTypeName can't be validated");
}
Type validatedType = Type.GetType(SourceTypeName);
if (validatedType == null)
{
throw new InvalidOperationException(
string.Format("{0}:{1}",
"Invalid SourceTypeName", SourceTypeName));
}
IEnumerable<MetadataTypeAttribute> mt = validatedType.GetCustomAttributes(typeof(MetadataTypeAttribute), false).OfType<MetadataTypeAttribute>();
if (mt.Count() > 0)
{
validatedType = mt.First().MetadataClassType;
}
return validatedType;
}
private FieldInfo GetValidatedProperty(Type source)
{
FieldInfo field = source.GetField(PropertyName);
if (field == null)
{
throw new InvalidOperationException(
string.Format("{0}:{1}",
"Validated Property Does Not Exists", PropertyName));
}
return field;
}
#endregion
}
This code only looks in the buddy class. If you want it to check an actual class and then its buddy class, you'll have to modify it accordingly. I did not bother doing that because usually if you are using a buddy class for validation attributes it's because you are not able to use the attributes in the main entity class (e.g. Entity Framework).
For model validation in web forms I'm using DAValidation library. It supports validation on client side (including unobtrusive validation), extensibility based on same principles as in MVC. It is MS-PL licensed and available via Nuget.
And here is bit out of date article describing with what thoughts control was build.
I was wondering if it is possible to disable the Required validation attribute in certain controller actions. I am wondering this because on one of my edit forms I do not require the user to enter values for fields that they have already specified previously. However I then implement logic that when they enter a value it uses some special logic to update the model, such as hashing a value etc.
Any sugestions on how to get around this problem?
EDIT:
And yes client validation is a problem here to, as it will not allow them to submit the form without entering a value.
This problem can be easily solved by using view models. View models are classes that are specifically tailored to the needs of a given view. So for example in your case you could have the following view models:
public UpdateViewView
{
[Required]
public string Id { get; set; }
... some other properties
}
public class InsertViewModel
{
public string Id { get; set; }
... some other properties
}
which will be used in their corresponding controller actions:
[HttpPost]
public ActionResult Update(UpdateViewView model)
{
...
}
[HttpPost]
public ActionResult Insert(InsertViewModel model)
{
...
}
If you just want to disable validation for a single field in client side then you can override the validation attributes as follows:
#Html.TextBoxFor(model => model.SomeValue,
new Dictionary<string, object> { { "data-val", false }})
I know this question has been answered a long time ago and the accepted answer will actually do the work. But there's one thing that bothers me: having to copy 2 models only to disable a validation.
Here's my suggestion:
public class InsertModel
{
[Display(...)]
public virtual string ID { get; set; }
...Other properties
}
public class UpdateModel : InsertModel
{
[Required]
public override string ID
{
get { return base.ID; }
set { base.ID = value; }
}
}
This way, you don't have to bother with client/server side validations, the framework will behave the way it's supposed to. Also, if you define a [Display] attribute on the base class, you don't have to redefine it in your UpdateModel.
And you can still use these classes the same way:
[HttpPost]
public ActionResult Update(UpdateModel model)
{
...
}
[HttpPost]
public ActionResult Insert(InsertModel model)
{
...
}
You can remove all validation off a property with the following in your controller action.
ModelState.Remove<ViewModel>(x => x.SomeProperty);
#Ian's comment regarding MVC5
The following is still possible
ModelState.Remove("PropertyNameInModel");
Bit annoying that you lose the static typing with the updated API. You could achieve something similar to the old way by creating an instance of HTML helper and using NameExtensions Methods.
Client side
For disabling validation for a form, multiple options based on my research is given below. One of them would would hopefully work for you.
Option 1
I prefer this, and this works perfectly for me.
(function ($) {
$.fn.turnOffValidation = function (form) {
var settings = form.validate().settings;
for (var ruleIndex in settings.rules) {
delete settings.rules[ruleIndex];
}
};
})(jQuery);
and invoking it like
$('#btn').click(function () {
$(this).turnOffValidation(jQuery('#myForm'));
});
Option 2
$('your selector here').data('val', false);
$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");
Option 3
var settings = $.data($('#myForm').get(0), 'validator').settings;
settings.ignore = ".input";
Option 4
$("form").get(0).submit();
jQuery('#createForm').unbind('submit').submit();
Option 5
$('input selector').each(function () {
$(this).rules('remove');
});
Server Side
Create an attribute and mark your action method with that attribute. Customize this to adapt to your specific needs.
[AttributeUsage(AttributeTargets.All)]
public class IgnoreValidationAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var modelState = filterContext.Controller.ViewData.ModelState;
foreach (var modelValue in modelState.Values)
{
modelValue.Errors.Clear();
}
}
}
A better approach has been described here Enable/Disable mvc server side validation dynamically
Personally I would tend to use the approach Darin Dimitrov showed in his solution.
This frees you up to be able to use the data annotation approach with validation AND have separate data attributes on each ViewModel corresponding to the task at hand.
To minimize the amount of work for copying between model and viewmodel you should look at AutoMapper or ValueInjecter. Both have their individual strong points, so check them both.
Another possible approach for you would be to derive your viewmodel or model from IValidatableObject. This gives you the option to implement a function Validate.
In validate you can return either a List of ValidationResult elements or issue a yield return for each problem you detect in validation.
The ValidationResult consists of an error message and a list of strings with the fieldnames. The error messages will be shown at a location near the input field(s).
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if( NumberField < 0 )
{
yield return new ValidationResult(
"Don't input a negative number",
new[] { "NumberField" } );
}
if( NumberField > 100 )
{
yield return new ValidationResult(
"Don't input a number > 100",
new[] { "NumberField" } );
}
yield break;
}
The cleanest way here I believe is going to disable your client side validation and on the server side you will need to:
ModelState["SomeField"].Errors.Clear (in your controller or create an action filter to remove errors before the controller code is executed)
Add ModelState.AddModelError from your controller code when you detect a violation of your detected issues.
Seems even a custom view model here wont solve the problem because the number of those 'pre answered' fields could vary. If they dont then a custom view model may indeed be the easiest way, but using the above technique you can get around your validations issues.
this was someone else's answer in the comments...but it should be a real answer:
$("#SomeValue").removeAttr("data-val-required")
tested on MVC 6 with a field having the [Required] attribute
answer stolen from https://stackoverflow.com/users/73382/rob above
I was having this problem when I creating a Edit View for my Model and I want to update just one field.
My solution for a simplest way is put the two field using :
<%: Html.HiddenFor(model => model.ID) %>
<%: Html.HiddenFor(model => model.Name)%>
<%: Html.HiddenFor(model => model.Content)%>
<%: Html.TextAreaFor(model => model.Comments)%>
Comments is the field that I only update in Edit View, that not have Required Attribute.
ASP.NET MVC 3 Entity
AFAIK you can not remove attribute at runtime, but only change their values (ie: readonly true/false) look here for something similar .
As another way of doing what you want without messing with attributes I will go with a ViewModel for your specific action so you can insert all the logic without breaking the logic needed by other controllers.
If you try to obtain some sort of wizard (a multi steps form) you can instead serialize the already compiled fields and with TempData bring them along your steps. (for help in serialize deserialize you can use MVC futures)
What #Darin said is what I would recommend as well. However I would add to it (and in response to one of the comments) that you can in fact also use this method for primitive types like bit, bool, even structures like Guid by simply making them nullable. Once you do this, the Required attribute functions as expected.
public UpdateViewView
{
[Required]
public Guid? Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int? Age { get; set; }
[Required]
public bool? IsApproved { get; set; }
//... some other properties
}
As of MVC 5 this can be easily achieved by adding this in your global.asax.
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
I was looking for a solution where I can use the same model for an insert and update in web api. In my situation is this always a body content. The [Requiered] attributes must be skipped if it is an update method.
In my solution, you place an attribute [IgnoreRequiredValidations] above the method. This is as follows:
public class WebServiceController : ApiController
{
[HttpPost]
public IHttpActionResult Insert(SameModel model)
{
...
}
[HttpPut]
[IgnoreRequiredValidations]
public IHttpActionResult Update(SameModel model)
{
...
}
...
What else needs to be done?
An own BodyModelValidator must becreated and added at the startup.
This is in the HttpConfiguration and looks like this: config.Services.Replace(typeof(IBodyModelValidator), new IgnoreRequiredOrDefaultBodyModelValidator());
using Owin;
using your_namespace.Web.Http.Validation;
[assembly: OwinStartup(typeof(your_namespace.Startup))]
namespace your_namespace
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
Configuration(app, new HttpConfiguration());
}
public void Configuration(IAppBuilder app, HttpConfiguration config)
{
config.Services.Replace(typeof(IBodyModelValidator), new IgnoreRequiredOrDefaultBodyModelValidator());
}
...
My own BodyModelValidator is derived from the DefaultBodyModelValidator. And i figure out that i had to override the 'ShallowValidate' methode. In this override i filter the requierd model validators.
And now the IgnoreRequiredOrDefaultBodyModelValidator class and the IgnoreRequiredValidations attributte class:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web.Http.Controllers;
using System.Web.Http.Metadata;
using System.Web.Http.Validation;
namespace your_namespace.Web.Http.Validation
{
public class IgnoreRequiredOrDefaultBodyModelValidator : DefaultBodyModelValidator
{
private static ConcurrentDictionary<HttpActionBinding, bool> _ignoreRequiredValidationByActionBindingCache;
static IgnoreRequiredOrDefaultBodyModelValidator()
{
_ignoreRequiredValidationByActionBindingCache = new ConcurrentDictionary<HttpActionBinding, bool>();
}
protected override bool ShallowValidate(ModelMetadata metadata, BodyModelValidatorContext validationContext, object container, IEnumerable<ModelValidator> validators)
{
var actionContext = validationContext.ActionContext;
if (RequiredValidationsIsIgnored(actionContext.ActionDescriptor.ActionBinding))
validators = validators.Where(v => !v.IsRequired);
return base.ShallowValidate(metadata, validationContext, container, validators);
}
#region RequiredValidationsIsIgnored
private bool RequiredValidationsIsIgnored(HttpActionBinding actionBinding)
{
bool ignore;
if (!_ignoreRequiredValidationByActionBindingCache.TryGetValue(actionBinding, out ignore))
_ignoreRequiredValidationByActionBindingCache.TryAdd(actionBinding, ignore = RequiredValidationsIsIgnored(actionBinding.ActionDescriptor as ReflectedHttpActionDescriptor));
return ignore;
}
private bool RequiredValidationsIsIgnored(ReflectedHttpActionDescriptor actionDescriptor)
{
if (actionDescriptor == null)
return false;
return actionDescriptor.MethodInfo.GetCustomAttribute<IgnoreRequiredValidationsAttribute>(false) != null;
}
#endregion
}
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public class IgnoreRequiredValidationsAttribute : Attribute
{
}
}
Sources:
Using string debug = new StackTrace().ToString() to find out who is
handeling the model validation.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/configuring-aspnet-web-api to know how set my own validator.
https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Http/Validation/DefaultBodyModelValidator.cs to figure out what this validator is doing.
https://github.com/Microsoft/referencesource/blob/master/System.Web/ModelBinding/DataAnnotationsModelValidator.cs to figure out why the IsRequired property is set on true. Here you can also find the original Attribute as a property.
If you don't want to use another ViewModel you can disable client validations on the view and also remove the validations on the server for those properties you want to ignore. Please check this answer for a deeper explanation https://stackoverflow.com/a/15248790/1128216
In my case the same Model was used in many pages for re-usability purposes. So what i did was i have created a custom attribute which checks for exclusions
public class ValidateAttribute : ActionFilterAttribute
{
public string Exclude { get; set; }
public string Base { get; set; }
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!string.IsNullOrWhiteSpace(this.Exclude))
{
string[] excludes = this.Exclude.Split(',');
foreach (var exclude in excludes)
{
actionContext.ModelState.Remove(Base + "." + exclude);
}
}
if (actionContext.ModelState.IsValid == false)
{
var mediaType = new MediaTypeHeaderValue("application/json");
var error = actionContext.ModelState;
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, error.Keys, mediaType);
}
}
}
and in your controller
[Validate(Base= "person",Exclude ="Age,Name")]
public async Task<IHttpActionResult> Save(User person)
{
//do something
}
Say the Model is
public class User
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Range(18,99)]
public string Age { get; set; }
[MaxLength(250)]
public string Address { get; set; }
}
This one worked for me:
$('#fieldId').rules('remove', 'required');
Yes it is possible to disable Required Attribute. Create your own custom class attribute (sample code called ChangeableRequired) to extent from RequiredAtribute and add a Disabled Property and override the IsValid method to check if it is disbaled. Use reflection to set the disabled poperty, like so:
Custom Attribute:
namespace System.ComponentModel.DataAnnotations
{
public class ChangeableRequired : RequiredAttribute
{
public bool Disabled { get; set; }
public override bool IsValid(object value)
{
if (Disabled)
{
return true;
}
return base.IsValid(value);
}
}
}
Update you property to use your new custom Attribute:
class Forex
{
....
[ChangeableRequired]
public decimal? ExchangeRate {get;set;}
....
}
where you need to disable the property use reflection to set it:
Forex forex = new Forex();
// Get Property Descriptor from instance with the Property name
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(forex.GetType())["ExchangeRate"];
//Search for Attribute
ChangeableRequired attrib = (ChangeableRequired)descriptor.Attributes[typeof(ChangeableRequired)];
// Set Attribute to true to Disable
attrib.Disabled = true;
This feels nice and clean?
NB: The validation above will be disabled while your object instance is alive\active...