Custom attributes not behaving like data annotations - c#

I am trying to create a custom attribute in console application but it is not working. My custom attribute never gets called. I found a good example here Custom Attribute not being hit
but not happy with its implementation.
I am wondering how data annotations works in MVC. we don't have to call it separately.
Is MVC calling those data annotations attribute behind the scene?
I wish to create custom attribute that I can use it on any class property same like data annotations attribute. But calling it separately like in above link is not what i am looking.
Here is what I have tried:
using System;
namespace AttributePractice
{
[AttributeUsage(AttributeTargets.Property)]
public class CustomMessageAttribute : Attribute
{
public static readonly CustomMessageAttribute Default = new CustomMessageAttribute();
protected string Message { get; set; }
public CustomMessageAttribute() : this(string.Empty)
{
Console.WriteLine("Default message is empty");
}
public CustomMessageAttribute(string message)
{
Message = message;
}
public string MyMessage =>
Message;
public override bool Equals(object obj)
{
if (obj == this)
return true;
if (obj is CustomMessageAttribute customMessageAttribute)
return customMessageAttribute.Message == MyMessage;
return false;
}
public override int GetHashCode()
{
return MyMessage.GetHashCode();
}
public override bool IsDefaultAttribute()
{
return Equals(Default);
}
}
public class Person
{
//This never works
// I am looking to use this attribute anywhere without calling it
// separately , same like data annotations
[CustomMessage("Hello world")]
public string Name { get; set; }
public int Age { get; set; }
public void DisplayPerson()
{
Console.WriteLine(Name);
Console.WriteLine(Age);
}
}
internal static class Program
{
private static void Main(string[] args)
{
var personObj = new Person
{
Name = "Tom",
Age = 28
};
personObj.DisplayPerson();
}
}
}
Can anybody tell me how to make my custom attribute works like data annotation way?

yes, if you need 10 custom attributes, you should create 10 separate.

Related

Why is a default interface method used instead of a class field?

I have code like below. Interface with default implementation. And the user who uses this interface. But for some reason in the switch case my code uses the default implementation of the interface for the "Name' instead of the class implementation. What should i change to see "Ben" in console?
namespace ConsoleApp1
{
public interface IUser
{
// Interface with default implementation
public string Name { get => "Tom"; }
}
// User using this interface
public class BenUser : IUser
{
public string Name = "Ben";
}
public static class MainClass
{
public static void ShowName(IUser user)
{
switch (user.Name)
{
case "Ben": // I expected the code to run here
Console.WriteLine("Ben");
break;
case "Tom": // But the code goes here
Console.WriteLine("Tom");
break;
}
}
static void Main()
{
// Create a user with Name "Ben"
var ben = new BenUser();
ShowName(ben); // In console i see "Tom" for some reason
}
}
}
I can't figure out why the code is behaving like this.
As mentioned in comments, you need to implement the interface using the same shape in your class - as a property with a get.
public interface IUser
{
// Interface with default implementation
public string Name { get => "Tom"; }
}
// User using this interface
public class BenUser : IUser
{
public string Name { get => "Ben"; }
}
public static class MainClass
{
public static void ShowName(IUser user)
{
switch (user.Name)
{
case "Ben": // I expected the code to run here
System.Console.WriteLine("Ben");
break;
case "Tom": // But the code goes here
System.Console.WriteLine("Tom");
break;
}
}
static void Main()
{
// Create a user with Name "Ben"
var ben = new BenUser();
ShowName(ben); // In console i see "Tom" for some reason
}
}
This is my edit to show some more standard practices, please read through the comments and see if it makes anything more clear. The standard practice for creating members is to use accesslevel Type VariableName { get; set; }
namespace ConsoleApp1
{
public interface IUser
{
//denotes that this is set by construction, cannot be set afterwards
public string Name { get; }
}
// User using this interface
public class BenUser : IUser
{
// Standard 'getter' only member with a compiled return value
public string Name
{
get
{
return "Ben";
}
}
}
public class User : IUser
{
// private settable string to use with construction
private string _name;
// constructor
public User(string userName)
{
// sets the private variable to desired value
_name = userName;
}
// public 'getter' that returns the set value
public string Name
{
get
{
return _name;
}
}
}
public static class MainClass
{
public static void ShowName(IUser user)
{
Console.WriteLine(user.Name);
}
static void Main()
{
// Create a user with static Name "Ben"
var ben = new BenUser();
ShowName(ben);
// Create a user with variable Name set as "Carl"
var carl = new User("Carl");
ShowName(carl);
}
}
}
The Name in IUser is a property while Name in BenUser is a field. With your code when we do user.Name it calls the get method defined in IUser instead of getting value of Name field from BenUser. Here is a sample implementation for fixing your bug.
public class BenUser : IUser
{
public string Name { get => "Ben"; }
}
I would recommend to not do it the way you are doing because Name identifier has become embiguos

Add property to all responses in asp.net core

I have an API with multiple endpoints. I'd like to add a property to all endpoint responses, without adding it to each endpoint response model individually.
Ex:
public class MyClass
{
public string MyProperty { get; set; } = "Hello";
}
public class MyOtherClass
{
public string MyOtherProperty { get; set; } = "World";
}
public class MyController : ControllerBase
{
[HttpPost]
public async Task<ActionResult<MyClass>> EndpointOne(POSTData data)
{
// implementation omitted
}
[HttpPost]
public async Task<ActionResult<MyOtherClass>> EndpointTwo(POSTOtherData otherData)
{
// implementation omitted
}
}
Calling either endpoint returns a JSON representation of MyClass or MyOtherClass as appropriate - i.e.
{ "MyProperty":"Hello" } or { "MyOtherProperty":"World" }
I want to add a property, say a string ApiName, to all endpoints in the API, so that the result of the above code would be either (as appropriate)
{ "MyProperty":"Hello", "ApiName":"My awesome API" }
or
{ "MyOtherProperty":"World", "ApiName":"My awesome API" }
Is there a way to hook into the JSON-stringified result just before returning and add a top-level property like that? If so, I presume I'd have to wire it up in startup.cs, so I've been looking at app.UseEndpoints(...) methods, but haven't found anything that's worked so far. Either it's not added the property, or it's replaced the original result with the new property.
Thanks in advance!
Use Newtonsoft.Json in your net web api
Register a custom contract resolver in Startup.cs:
builder.Services.AddControllers()
.AddNewtonsoftJson(options => options.SerializerSettings.ContractResolver = CustomContractResolver.Instance);
The implementation:
public class CustomContractResolver : DefaultContractResolver {
public static CustomContractResolver Instance { get; } = new CustomContractResolver();
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
// add new property
...
properties.Add(newProp);
return properties;
}}
See more Json.net Add property to every class containing of a certain type
You can add a base class with the shared property. Should work for both XML and JSON.
public class MyApiClass
{
public string ApiName => "MyAwesomeApi";
}
public class MyClass : MyApiClass
{
public string MyProperty { get; set; } = "Hello";
}
public class MyOtherClass : MyApiClass
{
public string MyOtherProperty { get; set; } = "World";
}
public class MyController : ControllerBase
{
[HttpPost]
public async Task<ActionResult<MyClass>> EndpointOne(POSTData data)
{
// implementation omitted
}
[HttpPost]
public async Task<ActionResult<MyOtherClass>> EndpointTwo(POSTOtherData otherData)
{
// implementation omitted
}
}
My 0.02 cents says to implement an abstract base class.
Abstract class inheritance look similar to a standard inheritance.
public class MyClass:MyAbstractClass
{
[JsonPropertyName("Class Property")]
public string MyProperty { get; set; } = "Hello";
}
public class MyOtherClass:MyAbstractClass
{
[JsonPropertyName("Class Property")]
public string MyOtherProperty { get; set; } = "World";
}
However the abstract class will allow you to implement additional features in the event you need them in the future.
public abstract class MyAbstractClass{
[JsonPropertyName("API Name")]
public string ApiName{get;set;}="My Aweomse API";
//Just a thought if you want to keep track of the end point names
//while keeping your object names the same
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public string EndPointName{
get{
return get_endpoint_name();
}}
private string get_endpoint_name(){
return this.GetType().Name;
}
//May as well make it easy to grab the JSON
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public string As_JSON{
get {
return to_json();
}}
private string to_json(){
object _myObject = this;
string _out;
JsonSerializerOptions options =
new JsonSerializerOptions {
WriteIndented = true };
_out =
JsonSerializer.Serialize(_myObject, options);
return _out;
}
}
Probably should have implemented a generic return object, then you could just loop through the task results. I suppose you still can if you have the task return only the JSON string.
public static void run(){
Task<MyClass> _t0 = task0();
Task<MyOtherClass> _t1 = task1();
Task[] _tasks = new Task[]{_t0,_t1};
Task.WhenAll(_tasks).Wait();
Console.WriteLine(""
+$"{_t1.Result.ApiName}:\n"
+$"End Point: {_t1.Result.EndPointName}:\n"
+$"JSON:\n{_t1.Result.As_JSON}");
Console.WriteLine(""
+$"{_t0.Result.ApiName}:\n"
+$"End Point: {_t0.Result.EndPointName}:\n"
+$"JSON:\n{_t0.Result.As_JSON}");
}
private static Task<MyClass> task0(){
return Task.Run(()=>{
Console.WriteLine("Task 0 Doing Something");
return new MyClass();
});
}
private static Task<MyOtherClass> task1(){
return Task.Run(()=>{
Console.WriteLine("Task 1 Doing Something");
return new MyOtherClass();
});
}
And of course the aweosome...awesome:-) results:
Another thought is that you could implement your two different tasks as abstract methods, but that's a different conversation all together.
In addition to all of the great answers, I prefer to use Action Filter and ExpandoObject.
In Program File you should add your custom action Filter.
builder.Services.AddControllers(opt =>
{
opt.Filters.Add<ResponseHandler>();
});
and ResponseHandler acts like below:
public class ResponseHandler : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (var propertyInfo in (context.Result as ObjectResult).Value.GetType().GetProperties())
{
var currentValue = propertyInfo.GetValue((context.Result as ObjectResult).Value);
expando.Add(propertyInfo.Name, currentValue);
}
dynamic result = expando as ExpandoObject;
result.ApiName = context.ActionDescriptor.RouteValues["action"].ToString();
context.Result = new ObjectResult(result);
}
public void OnActionExecuting(ActionExecutingContext context)
{
}
}

How to skip a Unit Test at runtime?

Thanks in advance!
We have some Automation tests using the selenium web driver which are great and provide a really good regression pack.
The problem is now we have feature toggles in our code. So I need to say ignore these tests unless that feature toggle is turned On/ Off. I can't find anything really searching Google.
Ideally I don't want a 'if' statement at the top of the Feature tests but it looks like it's going to be the main way. My initial thoughts where to create a custom attribute
public class IsFeatureFlagTurnedOn : Attribute
{
public IsFeatureFlagTurnedOn(string featureToggleName)
{
FeatureToggleName = featureToggleName;
}
public string FeatureToggleName {get;}
}
public class MyTests
{
[TestMethod]
[IsFeatureFlagTurnedOn("MyFeature1")]
public void ItShould()
{
// only run if MyFeature1 is turned on
}
}
I some how need to hook into the MSTest pipeline and say if this attribute is present and the logic for MyFeature1 is turned off then don't run this test - Looked at dynamically adding the [Ignore] but with no luck.
This is running through VSTS and I could use [TestCategories] but I'd have to keep updating the pipeline to which feature is turned on/off which I don't want to do.
Any help or suggestions would be great!
MSTest v2 now has a lot of extensibility points, and you can achieve this by extending the TestMethodAttribute. First we add two attribute arguments, a string for a property name and a Type that has the property. Then we override the Execute method and invoke the property via reflection. If the result is true, we'll execute the test as normal, otherwise we return an 'inconclusive` test result.
public class TestMethodWithConditionAttribute : TestMethodAttribute
{
public Type ConditionParentType { get; set; }
public string ConditionPropertyName { get; set; }
public TestMethodWithConditionAttribute(string conditionPropertyName, Type conditionParentType)
{
ConditionPropertyName = conditionPropertyName;
ConditionParentType = conditionParentType;
}
public override TestResult[] Execute(ITestMethod testMethod)
{
if (ConditionParentType.GetProperty(ConditionPropertyName, BindingFlags.Static | BindingFlags.Public)?.GetValue(null) is bool condiiton && condiiton)
{
return base.Execute(testMethod);
}
else
{
return new TestResult[] { new TestResult { Outcome = UnitTestOutcome.Inconclusive } };
}
}
}
Now we can use our new attribute like this:
[TestClass]
public class MyTests
{
[TestMethodWithCondition(nameof(Configuration.IsMyFeature1Enabled), typeof(Configuration))]
public void MyTest()
{
//...
}
}
public static class Configuration
{
public static bool IsMyFeature1Enabled => false;
}
The above is a very generic solution. You could also customize it a little more to your particular use case to perhaps avoid quite so much verbosity in the attribute declaration:
public class TestMethodForConfigAttribute : TestMethodAttribute
{
public string Name { get; set; }
public TestMethodForConfigAttribute(string name)
{
Name = name;
}
public override TestResult[] Execute(ITestMethod testMethod)
{
if (IsConfigEnabled(Name))
{
return base.Execute(testMethod);
}
else
{
return new TestResult[] { new TestResult { Outcome = UnitTestOutcome.Inconclusive } };
}
}
public static bool IsConfigEnabled(string name)
{
//...
return false;
}
}
And use it like:
[TestClass]
public class MyTests
{
[TestMethodForConfig("MyFeature1")]
public void MyTest()
{
//...
}
}
Based on my reading of this, you may need to use Assert.Inconclusive

C# custom attribute validation in console environment

My question is about validation using custom attributes in C#.
I don't quite understand how the validation works. I have declared an attribute with the validation rule in it but when the error should be thrown it is not.
Attribute:
[AttributeUsage(AttributeTargets.Property)]
public class NotNullAttribute : Attribute
{
public bool IsValid(object value)
{
if (value is string && (string)value != "")
{
return false;
}
return true;
}
}
Inside the attribute I check if the property is of type string and if its value is an empty string because that is what I have to check.
The task is to check if a property is a string and if its an empty string then its not valid, otherwise it is.
My Person class:
class Person
{
[NotNull]
public string Name { get; set; }
}
Here I am applying the custom attribute.
Main method:
class Program
{
static void Main(string[] args)
{
Person p1 = new Person();
p1.Name = "";
Console.WriteLine("Validation done");
Console.ReadKey();
}
}
This is where I instantiate the Person class and assign an empty string to the Name property. This is where the error should be thrown I guess.
So my question is why isn't the validation applied? Should I have called the IsValid method from the attribute it self somehow?
I would take some explanation about this, thank you in advance!
The attribute itself is just a "decorator" of the property. If nothing calls it, it will not be automatically executed nor used.
In your case, however, I don't see the point of using an attribute, when you can use property itself:
private string _name = "";
public string Name
{
get
{
return _name;
}
set
{
if ( string.IsNullOrEmpty(value) )
{
//throw or fallback
}
else
{
_name = value;
}
}
}
Doing basic value validation is exactly the job property setters are great for. In case someone uses an invalid value, you can throw an exception, or set a fallback value for example.
If you would still prefer using attributes, you still need to have some code that performs the validation itself. And still, anyone can assign any valid value to the property, unless validation is performed.
For example ASP.NET MVC uses attribute validation during Model Binding - it checks the validation attributes on the bound model class and verifies it before the action method begins executing.
Example of attribute validation
Here is a simple example of how to make your code work with reflection.
First here is a slightly updated version of the validation attribute:
[AttributeUsage(AttributeTargets.Property)]
public class NotNullAttribute : Attribute
{
public bool IsValid(object value)
{
if (!string.IsNullOrEmpty(value as string))
{
return false;
}
return true;
}
}
Your code actually only allowed a null or "" value, which I guess is opposite of what you wanted. This version is valid only when the string is not null and not empty.
Now create a Validate method in your Program class:
private static bool Validate(object model)
{
foreach (var propertyInfo in model.GetType().GetProperties())
{
foreach (var attribute in propertyInfo.GetCustomAttributes(true))
{
var notNullAttribute = attribute as NotNullAttribute;
if (notNullAttribute != null)
{
if (!notNullAttribute.IsValid(propertyInfo.GetValue(model)))
{
return false;
}
}
}
}
return true;
}
This basically gathers all properties of the type of the passed in parameter, checks all attributes of the properties for NotNullAttribute and then executes the attribute's IsValid method against the current value from the model.
Finally here is how you can call it from Main:
static void Main(string[] args)
{
Person p1 = new Person();
p1.Name = "d";
if (Validate(p1))
{
Console.WriteLine("Valid");
}
else
{
Console.WriteLine("Invalid");
}
Console.WriteLine("Validation done");
Console.ReadKey();
}
Now, if you are planning on adding more validation attributes, I would create an interface first:
public interface IValidationAttribute
{
bool IsValid(object value);
}
Then derive all your validation attributes from IValidationAttribute and in Validate method use IValidationAttribute in place of NotNullAttribute. This way the code becomes more future-proof as you can just program against the interface and add new validation attributes anytime.
public class BankAccount
{
public enum AccountType
{
Saving,
Current
}
[Required(ErrorMessage="First Name Required")]
[MaxLength(15,ErrorMessage="First Name should not more than 1`5 character")]
[MinLength(3,ErrorMessage="First Name should be more than 3 character")]
public string AccountHolderFirstName { get; set; }
[Required(ErrorMessage="Last Name Required")]
[MaxLength(15,ErrorMessage="Last Name should not more than 1`5 character")]
[MinLength(3,ErrorMessage="Last Name should be more than 3 character")]
public string AccountHolderLastName { get; set; }
[Required]
[RegularExpression("^[0-9]+$", ErrorMessage = "Only Number allowed in AccountNumber")]
public string AccountNumber { get; set; }
public AccountType AcType { get; set; }
[AccountBalaceCheckAttribute]
public double AccountBalance { get; set; }
}
How to Validate
public class GenericValidator
{
public static bool TryValidate(object obj, out ICollection<ValidationResult> results)
{
var context = new ValidationContext(obj, serviceProvider: null, items: null);
results = new List<ValidationResult>();
return Validator.TryValidateObject(
obj, context, results,
validateAllProperties: true
);
}
}
Example
static void Main(string[] args)
{
var bankAccount = new BankAccount();
ICollection<ValidationResult> lstvalidationResult;
bool valid = GenericValidator.TryValidate(bankAccount, out lstvalidationResult);
if (!valid)
{
foreach (ValidationResult res in lstvalidationResult)
{
Console.WriteLine(res.MemberNames +":"+ res.ErrorMessage);
}
}
Console.ReadLine();
}

Conditionally serialize a object in a collection using Json.net

There is tons of info about skipping Properties based on conditionals, but I would like to skip the entire object based on conditions within the object's class. I would like a solution that is contained within the object's class if at all possible. Keep in mind this is a collection of myObj that I am serializing.
public class myObj
{
bool conditional;
ShouldSerialize()
{
return conditional;
}
}
Or
public class myObj
{
[JsonCondition]
public bool conditional{get;}
}
Or even
[JsonCondition(typeof(MyConditionChecker))]
public class myObj
{
public bool conditional{get;}
}
class MyConditionChecker: JsonCondition
{
public override bool CanConvert(object sourceObj)
{
return (sourceObj as myObj).conditional;
}
}
What I got from your comments you would be best served creating your own wrapper around Json that applies the filtering.
public interface IConditionalSerializer
{
bool ShouldBeSerialized();
}
public static class FilteredSerializer
{
public static string SerializeConditional<T>(IEnumerable<T> input)
where T : IConiditionalSerializer
{
return JsonConvert.SerializeObject(input.Where(e => e.ShouldBeSerialized()));
}
}
public class Demo : IConditionalSerializer
{
public bool ShouldBeSerialized() => false;
}
You might also replace the interface with a reflection approach, but keep in mind the performance loss.
public interface IConiditionChecker
{
bool ShouldBeSerialized(object instance);
}
public class ConditionAttribute : Attribute
{
public Type ConditionChecker { get; set; }
}
public static class FilteredSerializer
{
public static string SerializeConditional(IEnumerable<object> input)
{
var matches = (from entry in input
let att = entry.GetType().GetCustomAttribute<ConditionAttribute>()
let hasChecker = att != null && att.ConditionChecker != null
let checker = hasChecker ? (IConiditionChecker)Activator.CreateInstance(att.ConditionChecker) : null
where checker.ShouldBeSerialized(entry)
select entry);
return JsonConvert.SerializeObject(matches);
}
}
[Condition(ConditionChecker = typeof(SomeChecker))]
public class Demo
{
}
Edit: Based on your comment you could do this. Only must decide wether to use opt-in or opt-out in the where-statement. It must ether be casted != null && casted.ShouldBeSerialized or what it currently says.
public interface IShouldBeSerialized
{
bool ShouldBeSerialized();
}
public static class FilteredSerializer
{
public static string SerializeConditional(IEnumerable<object> input)
{
var matches = (from entry in input
let casted = entry as IShouldBeSerialized
where casted == null || casted.ShouldBeSerialized()
select entry);
return JsonConvert.SerializeObject(matches);
}
}
public class Demo : IShouldBeSerialized
{
public bool ShouldBeSerialized()
{
return false;
}
}
If you're able to use the JSON.NET serializer, in terms of not serializing specific items within a collection, you could make the main collection non serializable, then add another filtered collection that does serialize.
public class Manager
{
[JsonIgnore]
public Employee[] Employees { get; set; }
[JsonProperty("Employees")]
public Employee[] SerializableEmployees
{
get { return Employees.Where(e => e.Name != "Bob").ToArray(); }
set { Employees = value; }
}
}
Alternatively, you could mark your class with the [JsonConverter] attribute and use a custom converter to check your condition. A similar approach that ignores a class entirely is detailed here.

Categories

Resources