.NET CORE List properties of an attribute - asp.net

I have multiple classes that use this custom attribute. All of them implement the same interface and they all have this custom attribute and have different names
public class NameAttribute : Attribute
{
public NameAttribute(string name)
{
this.Name = name;
}
public string Name { get; }
}
Is there a way to return a list of these names in the controller?

I'll answer my own question for if someone has the same problem in the future. This is what I did:
IEnumerable<Type> types = typeof(Startup).Assembly.ExportedTypes
.Where(type => type.IsClass && !type.IsAbstract)
.Where(type => type.GetInterface("IName") != null)
.Where(type => type.GetCustomAttribute<NameAttribute>() != null);
List<string> rules = new List<string>();
foreach (Type t in types)
{
rules.Add(t.GetCustomAttribute<NameAttribute>().Name);
}
Basicly what happens is that I look for all the exported types that implement an interface named "IName" and have the "NameAttribute" attribute. This will return a enumerable list with types.
Next it is possible to retrieve the custom attribute and put the name in an arraylist.

Related

ASP.NET Core Custom Parameter Binding

I have a situation in which I would like to do custom parameter binding for an api controller in ASP.NET core.In WebAPI 2.0 it was possible to perform custom binding to primitive types by implementing various interfaces such as IValueProvider and providing a ValueProviderFactory. This does not seem the case with ASP.NET core in as far as what I understand from the documentation I found here.
I did notice this SO post which lead me to this article which overrides the behavior for the MutableObjectModelBinder. It would appear I could do something along those lines such as:
[HttpGet]
[Route("api/{domain}/[controller]")]
public IEnumerable<string> Get([ModelBinder(BinderType = typeof(MyCustomBinder))]string orderby)
{
//Do stuff here
}
This doesn't necessarily seem right to me since I am just dealing with a primitive type however I cannot seem to find any documentation for another way of doing this.
Create a binder provider class for your custom type
public class MyCustomBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(MyCustom))
{
return new BinderTypeModelBinder(typeof(MyCustomBinder));
}
return null;
}
}
and register it in the services
services.AddMvc(c =>
{
c.ModelBinderProviders.Insert(0, new MyCustomBinderProvider());
});
And the custom binder can go like
public class MyCustomBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext.ModelType != typeof(MyCustom))
{
return TaskCache.CompletedTask;
}
var parameters = new Dictionary<string, string>();
foreach (var parameter in bindingContext.ModelType.GetProperties())
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(parameter.Name);
if (valueProviderResult.FirstValue != null)
{
parameters.Add(parameter.Name, valueProviderResult.FirstValue);
}
}
var result = Activator.CreateInstance(bindingContext.ModelType);
//write your custom code to map the result with the parameters
bindingContext.Result = ModelBindingResult.Success(result);
return TaskCache.CompletedTask;
}
}
Your custom type class
[ModelBinder(BinderType = typeof(MyCustomBinder))]
public class MyCustom
{
public int Page { get; set; }
public int Rows { get; set; }
}
and your controller can take the custom class as query string parameter
[HttpGet("data")]
public DataTransferObject GetData(MyCustom query)
{
}
Migrating OP's solution from the question to an answer, with meta commentary trimmed:
I just decided to go with a helper class to parse the parameter due to having to meet deadlines.

Custom Data Annotation attribute bool check

I am trying to make a custom data annotation attribute with a simple bool result, if the property have the data annotation, then perform an action. My objective is to make an array with all the properties that have the Filter dataanotation to later make a DropDownListFor in view with that information.
public class Foo
{
public string property1 { get; set; }
[Filter]
public string property2 { get; set; }
}
Then somewhere in the code:
IList<PropertyInfo> properties = typeof(Foo).GetProperties().ToList();
ArrayList propertiesThatCanBeFiltered = new ArrayList();
foreach (var propertyInfo in properties)
{
if (propertyInfo.Attributes("Filter").Exists)
{
propertiesThatCanBeFiltered.Add(propertyInfo.Name);
}
}
You need GetCustomAttribute<T> Documentation
And here how to apply it:
IList<PropertyInfo> properties = typeof(Foo).GetProperties().ToList();
ArrayList propertiesThatCanBeFiltered = new ArrayList();
foreach (var propertyInfo in properties)
{
var filterAttribute = propertyInfo.GetCustomAttribute<Filter>();
if (filterAttribute != null)
{
propertiesThatCanBeFiltered.Add(propertyInfo.Name);
}
}
I believe custom ActionFilters is what you are after:
http://msdn.microsoft.com/en-us/library/dd410056(v=vs.100).aspx
This is what you are stating in your question where when a certain attribute is applied to then execute some logic... AF's does just that.
Other than that, there is a way to create your own custom data annotation:
How to create Custom Data Annotation Validators
http://weblogs.asp.net/brijmohan/asp-net-mvc-3-custom-validation-using-data-annotations
but it depends exactly what you want to do. Do not get the 2 mixed up together.

How to get the elements from a generic List<T> in C#? [duplicate]

This question already has answers here:
Convert generic List/Enumerable to DataTable?
(28 answers)
Closed 8 years ago.
I have a class that converts a T List into a DataTable. And my problem is that I can not get the elements from the generic List T. T can be any model from entityFramework, like:
public class Test
{
public string userId { get; set; }
public string email { get; set; }
public string name { get; set; }
}
So List T is equivalent to List Test
My code is:
public class ConvertListToDataTable<T>
{
public T Field;
public DataTable ConvertTest<T>(List<T> item)
{
DataTable dT = new DataTable();
foreach(T t in item)
{
// here I want to get the elements from T and put them into the DataTable
}
return dT;
}
}
I know how to procces the dataTable, but I don't know how to get the 'userId', 'email', 'name' from the list
The reason why you cannot access just any property from an object of type T is because T could be literally anything - from a generics standpoint how can you know upfront what properties type T has?
If you happen to know that all objects are based on a common interface or base class then you could apply a generic constraint to your ConvertListToDataTable<T> class; this would allow the compiler to know upfront that some properties are available to that type at a base level.
But if you want to allow T to be any type at all then #MrFox is correct in that you would need to use Reflection to view the properties the type has at runtime and fill your DataTable that way.
Reflection can solve this:
public void Test(object t)
{
var properties = t.GetType().GetProperties();
foreach (var p in properties)
{
dT.Columns.Add(new DataColumn(p.Name, p.PropertyType));
}
var row = dT.NewRow();
int col = 0;
foreach (var p in properties)
{
row[col++] = p.GetValue(t);
}
}
You can give the GetProperties method arguments if you only want properties of a certain type.

AutoMapper and reflection

My shared hosting company doesn't allow Reflection.
How can I use AutoMapper?
Do I have to specify for each property a .ForMember?
Mapper.CreateMap<Person, PersonData>()
.ForMember(dest => dest.Name, o => o.MapFrom(src => src.Name))
.ForMember(dest => dest.Address, o => o.MapFrom(src => src.Address));
thanks,
Filip
Automapper uses reflection.emit, are you sure you can use Automapper?
[Edit]
Dont know of any that uses without reflection, even the one I had created XmlDataMapper on CodePlex uses reflection. It would difficult to design one without reflection or reflection.emit
The simplest and basic way to do this would be this, you can use any of the two or both techniques.
public class ConversionHelper
{
public static ClassB Convert(ClassA item)
{
return new ClassB() { Id = item.Id, Name = item.Name };
}
public static List<ClassB> Convert(List<ClassA> list)
{
return list.Select(o => new ClassB() { Id = o.Id, Name = o.Name }).ToList();
}
}
public class ClassA
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ClassB
{
public int Id { get; set; }
public string Name { get; set; }
}
From the sample you have given where you are anyways trying to map property one by one, this is on the same lines, but with lesser code.
You cannot use Automapper or any other mapping architecture that I know of without reflection. This is logically obvious. How could you map two unknown entities to one another without using any of their reflected properties? Your only option in this case is to create a custom package to convert one object into another.
Not at all. AutoMapper did a great job on intelligent mapping. If the property name of your source and destination object is the same, AutoMapper will map this proprties automatically for you.

Using Moq to verify that a method was called

I have a class like:
public class Store
{
public Store()
{
Products = new List<Product>();
}
public IList<Product> Products {get; private set;}
public void AddProduct(int id, string productCode)
{
Product p = new Product();
p.Id = id;
p.ProductCode = productCode;
//Validate before adding
Products.Add(p); //How can i verify that this was called
}
}
Using Moq how can i verify that the Add method of the Products List was called? Can someone provide a simple example?
Well you can't really mock anything at the moment as the Products list is set up in the default constructor?
The easiest thing to do would be to assert against your products collection manually (i.e. just verify there's a product in there with the specified ID and Code) then you don't have to worry about mocking at all.
If you really want to use Moq to test this you need to provide a means to inject your Mock and get around your constructor, as an example you can provide two constructors
public class Store {
public Store() : this(new List<Product>()) {
}
public Store(IList<Product> productList) {
Products = productList
}
//Implementation
}
You can then write a test against your add method as follows
[Test]
public AddProduct_WithIdAndProductCode_AddsProductToCollection() {
int productId = 0;
string productCode = "a";
var productListMock = new Mock<IList<Product>>();
Store store = new Store(productListMock.Object);
store.AddProduct(productId, productCode);
productListMock.Verify(pl =>
pl.Add(It.Is<Product>(p =>
p.Id == productId && p.ProductCode == productCode)));
}
Do you need to test that add was called or that the list now has the expected number of items?
Assert.True(store.Products.Count == 1);

Resources