I have a string field name consoleServerPort, and I want to trim all the white spaces inside it before saving it. I use to do so inside my controller class, as follow:-
public ActionResult Edit(FirewallJoin fj, FormCollection formValues)
{
fj.ConsoleServerPort = !String.IsNullOrEmpty(fj.ConsoleServerPort) ? fj. ConsoleServerPort.Trim() : "";
But I have to repeat this step on every action method. So I found another way of doing so once at the model level inside an Ivalidatable method as follow:-
public partial class TMSFirewall : IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(!String.IsNullOrEmpty(ConsoleServerPort)){
ConsoleServerPort = ConsoleServerPort.Trim();
}
So is my second approach sound valid? or it is better to use the first approach ?
Thanks
Edit
I am using entity Framework and i did the following
i tried the following inside my model class i added the following :-
[MetadataType(typeof(TMSSwitchPort_Validation))]
[Bind(Include = "PortNumber,SwitchID,TechnologyID")]
public partial class TMSSwitchPort //: IValidatableObject
{
}
then inside the MetadataType class i added the following :-
public class TMSSwitchPort_Validation
{
private string consoleServerPort;
[Required]
[StringLength(10)]
[Display(Name="Port Number1111")]
public String PortNumber
{
get { return this.consoleServerPort; }
set { this.consoleServerPort = value.Trim(); }
}
}
but the ConsoleServerPort will not be trimmed? can you advice what might be the problem ?
Thanks
Couldn't you do it on the property setter?
public class FirewallJoin
{
private string _consoleServerPort;
public string ConsoleServerPort
{
get
{
return _consoleServerPort;
}
set
{
_consoleServerPort = value.Trim();
}
}
}
Related
I'm trying to write a custom validation class for an ASP.NET Core web app I'm developing. I've found various examples of how to write custom client-side validation, such as this and this. These are all clear and make sense to me. However, my problem is that my model is defined within a .NET Standard library that other projects share. I cannot access the base classes I need to create the custom validation class from within this library.
Basically, I need to ensure that model.PropertyA is never greater than model.PropertyB. I'm aware that I could write some JavaScript that accomplishes this, but I'd prefer to utilize the existing ASP.NET Core validation techniques if possible.
I'd prefer to avoid any 3rd party dependencies to accomplish this, if possible.
hy,
Better to avoid Validation against Data Annotation because you don't have access to them in all cases , like the case you are describing;
One powerful package exist "FluentValidation "
you can create a model class and validate against properties
sample:
public class Person {
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}
full documentation : https://docs.fluentvalidation.net/en/latest/aspnet.html
and then you add a validator for your commands like the following sample :
public class CreatePersonCommandValidator :
AbstractValidator<CreatePersonCommand>
{
....
public CreateTodoListCommandValidator(IApplicationDbContext context)
{
_context = context;
RuleFor(v => v.Name)
.NotEmpty().WithMessage("Name is required.")
.MaximumLength(200).WithMessage("Name must not exceed 200 characters.");
}...
....
..
You could build a class extends the class from libraries. And extends IValidatableObject to implement Validation.
Base class is from librarie.
public class Base
{
public int PropertyA { get; set; }
public int PropertyB { get; set; }
}
MyClass is build for validation.
public class MyClass : Base, IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (PropertyA > PropertyB)
{
yield return new ValidationResult(
$"model.PropertyA {PropertyA} can't greater than model.PropertyB ." );
}
}
}
Test codes:
[HttpPost]
public IActionResult Add([FromBody]MyClass myClass)
{
if (ModelState.IsValid)
{
RedirectToAction("Index");
}
return View();
}
Test result:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
I am trying to use a custom attribute on a Entity class generated automatically by the Entity Framework.
The problem is how to add an property attribute on an existing field?
Here the point where I am right now:
// the custom attribute class
public class MyCustomAttribute : Attribute
{
public String Key { get; set; }
}
// Entity Framework class generated automatically
public partial class EntityClass
{
public String Existent { get; set; }
//...
}
// set a metadata class for my entity
[MetadataType(typeof(EntityClassMetaData))]
public partial class EntityClass
{
// if I add a new property to the entity, it works. This attribute will be read
[MyCustomAttribute(Key = "KeyOne" )]
public int newProp { get; set; }
}
public class EntityClassMetaData
{
// adding the custom attribute to the existing property
[MyCustomAttribute(Key = "keyMeta") ]
public String Existent { get; set; }
}
Running this test:
[TestMethod]
public void test1()
{
foreach (var prop in typeof(EntityClass).GetProperties())
{
var att = prop.GetCustomAttribute<MyCustomAttribute>();
if (att != null)
{
Console.WriteLine($"Found {att.Key}");
}
}
}
will produce:
Found KeyOne
Or the Metadata class store the attribute in a different way or only works for data annotations.
I am stuck here, how can I set and read custom attributes of the generated class without having to edit the generated file?
I came across this same problem today. I figured EF magic would do the trick and map the attribute across to each model property. Turns out it does, but only for EF data annotations and I couldn't find an answered solution to pull out custom attributes so made this function. Hope it helps dude.
private object[] GetMetadataCustomAttributes(Type T, string propName)
{
if (Attribute.IsDefined(T, typeof(MetadataTypeAttribute)))
{
var metadataClassType =
(T.GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault() as
MetadataTypeAttribute).MetadataClassType;
var metaDataClassProperty = metadataClassType.GetProperty(propName);
if (metaDataClassProperty != null)
{
return metaDataClassProperty.GetCustomAttributes(true);
}
}
return null;
}
I believe if you want to set an attribute in the metadata class, you have to use this syntax:
public class EntityClassMetaData
{
// adding the custom attribute to the existing property
[MyCustomAttribute(Key = "keyMeta") ]
public String Existent;
}
You must not have { get; set; } on your pre-existing property - just the property with the correct name and datatype.
I want to populate a viewmodel based on both Body content and Header content, I've tried to decorate with both attributes but only one or the other seems to be running and populating the value.
Moving the FromBody to the property causes the header value to be populated, having the FromBody in the param declaration on the controller causes the body Id to be populated.
Subsequently running TryUpdateModelAsync in the controller does populate both but this seems ugly and over the top.
Anyone have any ideas how to get this working?
public IActionResult GetAddress([FromBody]AddressDataViewModel model)
{
if (!this.ModelState.IsValid)
{
return this.BadRequest(this.ModelState);
}
return this.Ok(this.helper.GetAddress(model.Id));
}
public class AddressDataViewModel : BaseHttpRequestMeta
{
[Required]
public string Id { get; set; }
}
public class BaseHttpRequestMeta
{
[BindRequired]
[FromHeader(Name = "sessionid")]
public string SessionId { get; set; }
}
You could try and make your own binding source. Haven't tested this, but something like a hybrid binding source:
public class FromHeaderOrBodyAttribute : Attribute, IBindingSourceMetadata
{
public BindingSource BindingSource => new HeaderOrBodyBindingSource();
}
public class HeaderOrBindingSource : BindingSource
{
public HeaderOrBindingSource() : base("HeaderOrBody", "Header or Body binding source", true, true)
{
}
public override bool CanAcceptDataFrom(BindingSource bindingSource)
{
return bindingSource == BindingSource.Header
|| bindingSource == BindingSource.Body;
}
}
Then use the attribute on your action:
public IActionResult GetAddress([FromHeaderOrBody]AddressDataViewModel model)
{
}
Again, haven't tested this, but I thought the code was a bit too much just for a comment. Please respond with your results.
In my app, i have a edmx file with some partial classes representing my tables, and a context class wich i have the methods i need i.e GetMessages() and GetMessageById(long idMessage).
In that case, i use the GetMessages() method to fill a grid. Everything normal.
The Message entity class is something like this:
[Table("Message")]
public partial class Message
{
public long IdMessage{get;set;}
public long IdStatus{get;set;}
}
The problem is that i have another table that i have the StatusDescription that i need to get using the IdStatus.
I created another partial class with this property:
public partial class Message
{
private static readonly MessageRepository MessageRepository ;
static Message()
{
MessageRepository = new MessageRepository();
}
public string StatusDescription
{
get { return MessageRepository .GetMessageDescription(this.Cd_SchedulerStatus); }
}
}
And the method in the MessageRepository:
public MessageRepository()
{
_appContext= AppContext.GetContext();
}
public string GetMessageStatusDescription(int statusId)
{
var status = _appContext.Message.FirstOrDefault(id => id.IdStatus.Equals(statusId));
return status != null ? status.StatusDescription : string.Empty;
}
I know that it generates problems and it is not the best approach to deal with it, because im acessing the data inside the entity class, im having the n+1 problem, each time i send a new query to the database.
I would like to know if somebody have this problem and whats the best solution?
I suggest you create a new context for each message description request:
public string GetMessageStatusDescription(int statusId)
{
using (var appContext = AppContext.GetContext())
{
var status = appContext.Message.FirstOrDefault(id => id.IdStatus == statusId);
return status != null ? status.StatusDescription : string.Empty;
}
}
I am using Entity Framework 4.3.1, with auto-generated entities from the database.
From this, is there any way to set the default value to something? I don't want to put it in the auto-generated code since it will be overwritten.
I understand that it is possible to use partial classes, so I tried something like this, where entity is generated, and DESCRIPTION_ is the attribute I want to set to a default value.
namespace name.Models
{
public partial class ENTITY
{
public string DESCRIPTION_
{
set { _DESCRIPTION_ = "default string"; }
}
}
}
Maybe if somebody could give me an example that would be great!
The example you give means that DESCRIPTION can only ever be "default string"
You can set it in the constructor
namespace name.Models
{
public partial class ENTITY
{
private string defaultDescription = "some text";
public ENTITY() {
DESCRIPTION_ = defaultDescription;
}
}
}
or by switching your property to one with a backing field
namespace name.Models
{
public partial class ENTITY
{
private string _desc = "some default value";
public virtual string DESCRIPTION_ {get {return _desc} set {_desc = value;} }
}
}
You use OnCreated on the partial class:
public partial class ENTITY
{
partial void OnCreated()
{
DESCRIPTION_ = "default string";
}
}