I have an attribute for validation called Required() : BaseAttribute, and I can track it using the following code: (The BaseAttribute just implements the IsValid() Method.)
public static String Validate(object Object)
{
StringBuilder builder = new StringBuilder();
if (Object != null)
{
Type ObjectType = Object.GetType();
PropertyInfo[] Properties = ObjectType.GetProperties();
foreach (PropertyInfo Property in Properties)
{
object[] Attributes = Property.GetCustomAttributes(typeof(BaseAttribute), true);
foreach (object Attribute in Attributes)
builder.AppendLine(((BaseAttribute)Attribute).IsValid(Property, Object));
}
}
return builder.ToString();
}
The problem is, this works:
class roh {
[Required()]
public string dah { get; set; }
}
class main {
Console.WriteLine(Validate(new roh()));
}
but this doesn't:
class fus {
private roh _roh
public roh Roh {
get { if (_roh == null)
_roh = new roh;
return _roh; }
set { _roh = value; }
}
}
class roh {
[Required()]
public string Dah { get; set; }
}
class main {
Console.WriteLine(Validate(new fus()));
}
How can I modify my Validate method so that it can recursively find the custom attributes no matter how deep the object is?
You could use the Microsoft Enterprise Library. It has some build in validation blocks (similar in style to what you're using here) and does support recursive object validation down the object graph, I believe.
You reference the EntLib Validation DLL, and can either use the built-in validation or write your own. You can then validate it using a simple Validation.Validate(myObject) call.
Hope that might help :)
You already said the magic word - recursion. For every property you visit, call Validate on the object it stores, and voila.
One caveat is infinite recursion - this will work OK if your object graph is a tree. If it's more complex, you'll need to track which objects you have already visited.
Related
I mistakenly posted this question already at the SharePoint part.
I need to map one model onto an other. Everything works well but the last property throws a TargetParameterCountException. The property which throws the exception is called "Item" this property is not defined by me, I assume that this is a property from the dictionary.
I already tried to use all five parameters instead of only one (as described here Moq + Unit Testing - System.Reflection.TargetParameterCountException: Parameter count mismatch) but unfortunately i will get the same exception. I would really appreciate it if someone could help me.
Kinde Regards and Thanks
Sandro
That is a excerpt of the Source Model, all other properties are implemented in exactly the same way:
public class DataModel : Dictionary<string, object> {}
public class DiscussionDataModel : DataModel
{
public DiscussionDataModel(Dictionary dictionary) : base(dictionary){}
public FieldUserValue Author
{
get { return (FieldUserValue) this["Author"]; }
set { this["Author"] = value; }
}
public double AverageRating
{
get { return (double) this["AverageRating"]; }
set { this["AverageRating"] = value; }
}
}
And that is a excerpt the target Model, all other properties are implemented in exactly the same way:
public class DiscussionModel : BaseModel
{
public FieldUserValue Author { get; set; }
public double AverageRating { get; set; }
}
And this is the generic extension method to map the DataModel onto the BaseModel:
public static T ToModel(this DataModel dataModel) where T : BaseModel
{
try
{
T model = Activator.CreateInstance();
if (dataModel != null)
{
PropertyInfo[] propertyInfos = dataModel.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (PropertyInfo propertyInfo in propertyInfos)
{
object value = propertyInfo.GetValue(dataModel);
if (value == null) { break; }
PropertyInfo modelPropertyInfo = model.GetType().GetProperty(propertyInfo.Name);
modelPropertyInfo?.SetValue(model, value);
}
return model;
}
}
catch (Exception ex)
{
throw;
}
return null;
}
The problem is that the Item property is indexed, i.e. it has a parameter. C# normally does not allow this, but other .NET languages such as VB.NET do. Thus, this concept is known to the CLR and thus also to Reflection. In C#, there is only one way to create an indexed property, namely through an indexer. What this does at a CLR-level is to create an indexed propery called Item, so you might have just stumbled across an indexer.
So the solution is to check the property info whether it has parameters and continue the for loop if this is the case. There is no chance for you to know generically what objects to pass into an indexed property.
Just to clarify, I have this working using dynamic and MakeGenericType. But I cant help but think there is a better way to do this. What I am trying to do is create a "plug-in" loader, using Unity. I will just explain it as I post the code so you can get a sense for what I am doing.
First I'll just post the plug-in itself:
[RegisterAction("MyPlugin", typeof(bool), typeof(MyPlugin))]
public class MyPlugin: IStrategy<bool>
{
public IStrategyResult<bool> Execute(ISerializable info = null)
{
bool result;
try
{
// do stuff
result = true;
}
catch (Exception)
{
result = false;
}
return new StrategyResult<bool>
{
Value = result
};
}
}
Couple things to note here. First is the RegisterActionAttribute:
[AttributeUsage(AttributeTargets.Class)]
public sealed class RegisterActionAttribute : Attribute
{
public StrategyAction StrategyAction { get; }
public RegisterActionAttribute(string actionName, Type targetType, Type returnType, params string[] depdencies)
{
StrategyAction = new StrategyAction
{
Name = actionName,
StrategyType = targetType,
ResponseType = returnType,
Dependencies = depdencies
};
}
}
Then the interfaces:
public interface IStrategy<T>
{
IStrategyResult<T> Execute(ISerializable info = null);
}
public interface IStrategyResult<T>
{
bool IsValid { get; set; }
T Value { get; set; }
}
All fairly straight forward. The goal here is just to attach some meta-data to the class when it is loaded. The loading happens via unity using a wrapper that simply loads the assemblies in the bin directory using a file search pattern and adds it to a singleton class with a collection of StrategyActions. I don't need paste all the unity code here as I know it works and registers and resolves the assemblies.
So now to the meat of the question. I have a function on the singleton that executes actions. These are applied with Unity.Interception HandlerAttributes and passed a string like so (I can post the code for this but I didn't think it was relevant):
[ExecuteAction("MyPlugin")]
The handler calls the following execute function on the singleton class to "execute" functions that are registered (added to the collection).
public dynamic Execute(string action, params object[] parameters)
{
var strategyAction = _registeredActions.FirstOrDefault(a => a.Name == action);
if (strategyAction == null)
return null;
var type = typeof (IStrategy<>);
var generic = type.MakeGenericType(strategyAction.StrategyType);
var returnType = typeof (IStrategyResult<>);
var genericReturn = returnType.MakeGenericType(strategyAction.ResponseType);
var instance = UnityManager.Container.Resolve(generic, strategyAction.Name);
var method = instance.GetType().GetMethod("Execute");
return method.Invoke(instance, parameters);
}
This execute is wrapped in an enumerator call which returns a collection of results, which sorts to manage dependencies and what not (see below). These values are referenced by the caller using the Value property of ISTrategyResult{T} to do various things defined by other business rules.
public List<dynamic> ExecuteQueuedActions()
{
var results = new List<dynamic>();
var actions = _queuedActions.AsQueryable();
var sortedActions = TopologicalSort.Sort(actions, action => action.Dependencies, action => action.Name);
foreach(var strategyAction in sortedActions)
{
_queuedActions.Remove(strategyAction);
results.Add(Execute(strategyAction.Name));
}
return results;
}
Now mind you, this works, and I get the return type that is specified by the plugins RegisterAction attribute. As you can see I am capturing the Type of the plugin and the return type. I am using the "generic" variable to resolve the type with unity through the use of MakeGenericType, which works fine. I am also creating a generic representing the return type based on the type from the collection.
What I don't like here is having to use dynamic to return this value to a function. I can't figure out a way to return this as a IStrategyResult{T} because obviously the caller to "dynamic Execute(..." can not, at run-time, imply return type of the function. I mulled around with making the call to Execute with a MakeGenericMethod call as I actually have the expected type the StrategyAction. It would be cool if I could some how figure out away to return a strongly typed result of IStrategyResult{T} while determining the type of T during the call.
I do understand why I cannot do this with my current implementation I am just trying to find a way to wrap all this functionality without using dynamic. And was hoping somebody could provide some advice that might be useful. If that means wrapping this with other calls to non-generic classes or something like that, that would be fine as well if that is the only solution.
You need a more sweeping refactor than just figure out how to call your plugin.
There's no need for the [RegisterAction] attribute to hold targetType and returnType, these parameters to the attribute can easily get out of sync with code, making them a potential hole to fall into.
Then think from the other side of your setup: how do you consume the data, what do you do with your IStrategyResult<> - does it really have to be generic or there is a specific way you could encapsulate the type of results? I can't quite imagine a plugin system that returns "anything" to the host. The hint is really in your dynamic Execute(...) - your parameters and your result have both lost their strong typing, showing you that strong-typing the plugin is not helping with anything. Just use object or - better - make a StrategyResult class instead of the current interface and provide whatever properties are necessary there (I've added a few frivolous examples), such as:
public class StrategyResult{
public object Result{get;set;}
public Type ResultType {get;set;}
// frivolous examples
public bool IsError {get;set;}
public string ErrorMessage {get;set;}
// really off-the-wall example
public Func<StrategyHostContext,bool> ApplyResultToContext {get;set;}
public StrategyResult(){
}
public StrategyResult FromStrategy(IStrategy strategy){
return new StrategyResult{
ResultType = strategy.ResultType
}
}
public StrategyResult FromStrategyExecute(IStrategy strategy, ISerializable info = null){
var result = FromStrategy(strategy);
try{
strategy.Execute(info);
} catch (Exception x){
result.IsError = true;
result.ErrorMessage = x.Message;
}
}
}
Then your IStrategy becomes:
public interface IStrategy{
Type ResultType {get;}
void Initialize(SomeContextClassMaybe context);
StrategyResult Execute(ISerializable info = null);
}
You can also change your attribute to make it more efficient to load large plugins:
[AttributeUsage(AttributeTargets.Assembly)]
public sealed class AddinStrategyAttribute : Attribute
{
public Type StategyType {get; private set;}
public AddinStrategyAttribute(Type strategyType){
StrategyType = strategyType;
}
}
... and use the attribute like so:
[assembly:AddinStrategy(typeof(BoolStrategy))] // note it's outside the namespace
namespace MyNamespace{
public class BoolStrategy: IStrategy{
public Type ResultType { get{ return typeof(bool);}}
public void Initialize (SomeContextClassMaybe context){
}
public StrategyResult Execute(ISerializable info = null){
return StrategyResult.FromStrategyExecute(this,info);
}
}
}
Assuming that the caller of ExecuteActions does not have any knowledge about the T in any of the plugins or results and must work with dynamic or object anyway, then the following may work:
Infrastructure:
public interface IStrategy
{
IStrategyResult Execute(ISerializable info = null);
}
public interface IStrategyResult
{
bool IsValid { get; }
dynamic Value { get; }
}
public class StrategyResult<T> : IStrategyResult
{
public T Value { get; private set; }
public StrategyResult(T value) { this.Value = value; }
public bool IsValid { get { throw new NotImplementedException(); } }
dynamic IStrategyResult.Value { get { return this.Value; } }
}
[AttributeUsage(AttributeTargets.Class)]
public sealed class RegisterActionAttribute : Attribute
{
public List<string> Dependencies { get; private set; }
public RegisterActionAttribute(params string[] depdencies)
{
this.Dependencies = new List<string>(depdencies);
}
}
public class StrategyAction
{
public string Name;
public List<string> Dependencies;
}
public abstract class BasePlugin<T> : IStrategy
{
public IStrategyResult Execute(ISerializable info = null)
{
return new StrategyResult<T>(this.execute(info));
}
protected abstract T execute(ISerializable info);
}
Example plugin:
[RegisterAction]
public class MyFirstPlugin: BasePlugin<bool>
{
protected override bool execute(ISerializable info = null)
{
try
{
// do stuff
return true;
}
catch (Exception)
{
return false;
}
}
}
[RegisterAction("MyFirstPlugin")]
public class MySecondPlugin: BasePlugin<string>
{
protected override string execute(ISerializable info = null)
{
try
{
// do stuff
return "success";
}
catch (Exception)
{
return "failed";
}
}
}
Example execution engine:
public class Engine
{
public List<StrategyAction> registeredActions = new List<StrategyAction>();
private List<StrategyAction> queuedActions = new List<StrategyAction>();
public IStrategyResult Execute(string action, ISerializable info = null)
{
if (this.registeredActions.FirstOrDefault(a=>a.Name == action) == null) return null;
// This code did not appear to be used anyway
//var returnType = typeof (IStrategyResult<>); //var genericReturn = returnType.MakeGenericType(strategyAction.ResponseType);
var instance = (IStrategy) UnityManager.Container.Resolve(typeof(IStrategy), action);
return instance.Execute(info);
}
public List<IStrategyResult> ExecuteQueuedActions()
{
var results = new List<IStrategyResult>();
var actions = this.queuedActions.AsQueryable();
var sortedActions = TopologicalSort.Sort(actions, action => action.Dependencies, action => action.Name);
foreach(var strategyAction in sortedActions)
{
this.queuedActions.Remove(strategyAction);
results.Add(Execute(strategyAction.Name));
}
return results;
}
}
Note that when the plugins are loaded, the RegisterActionAttribute information along with the name of the plugin type loaded need to be combined into a StrategyAction instance and loaded into the registeredActions field of the engine.
The above allows the plugins to work with strong types but still allows the engine to deal with a variety of types. If you need the engine to work with more strongly typed data, then please provide an example of how the callers of ExecuteQueuedActions are expected to work with the results from ExecuteQueuedActions.
You got into this pickle by giving your RegisterActionAttribute constructor the returnType argument. Since you have only one Execute() method, you are forced to deal with the fact that the return type can be different types.
Using dynamic is about as good as it gets. You can make Execute() generic but then you'll have to deal with a mismatch between its type parameter and the attribute's ResponseType. Not one that the compiler can catch, this fails at runtime. It isn't generic.
Frankly, this strongly sounds like one flexibility too many. At the risk of interpreting the point of having a return type incorrectly, the outcome of a "registration action" is rather boolean. It worked or it didn't work. And is in fact the way you implemented it, your first plugin snippet does return bool.
With very high odds that you should not use bool either. Failure ought to make a bang, you'd throw an exception.
Why not define a super interface IStrategyResult like this:
interface IStrategyResult
{
Type ReturnType { get; }
}
interface IStrategyResult<T> : IStrategyResult
{
// your code here
}
Then define your execute like this:
public IStrategyResult Execute(string action, params object[] parameters)
And have your StrategyResult : IStrategyResult<T> class set the property to return typeof(T)
By convention you could assume (or enforce using inheritance on an abstract StrategyResult<T> : IStrategyResult<T> class) the T to be the same as the ReturnType property of the non-generic IStrategyResult interface.
I am using a custom model binder to bind my complex type.
Here's the model:
[ModelBinder(typeof(SupplierModelBinder))]
public class SupplierModel
{
public string VendorId { get; set; }
public string VendorName { get; set; }
public override string ToString()
{
return VendorId;
}
}
Here's the binder:
public class SupplierModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
string key = bindingContext.ModelName;
ValueProviderResult val = bindingContext.ValueProvider.GetValue(key);
if (val != null)
{
string s = val.AttemptedValue as string;
if (s != null)
{
return new SupplierModel() { VendorId = s };
}
}
return null;
}
}
I'm rendering the model using Html.ActionLink calls the UserModel's ToString method. When that GETs to the server it uses the result of that to bind the model.
This works great (I'm not bothered about the VendorName property here), however it does rely on overriding ToString in the model class so I can use that value in the model binder.
How can I separate the binding/unbinding of my complex type from the ToString method?
I don't want to have to override ToString just so my model gets rendered correctly for my binder to interpret. For other types I'll have to (de)serialise to JSON or simiar, which I don't want to be in ToString.
I've managed to figure out how to do this without using a custom binding. The trick is realising that if I have things like Supplier.VendorId="XXXX" as part of the query string of the action link that gets rendered then it gets mapped correctly.
I used reflection to see what HtmlHelper.ActionLink() does when it's passed an object, which is that it creates an instance of RouteValueDictionary<string, object>, which creates a key for each property of the object.
This default implementation is close to what I want, but I need it to deal with properties of properties.
Luckly there's an overload of ActionLink() that takes a RouteValueDictionary<string, object> directly, so that left me with the problem of constructing one with the Property.SubProperty type keys correctly.
I ended up with the code below, which firstly uses the RouteValueDictonary's constructor to get a key for each property.
Then it removes any that won't get bound according to the Bind attribute (if the class has one), which tidies up the resulting querystring quite a bit.
The main part it does though is to look for any properties of type ...Model (the type name ending with "Model") and add that object's properties to the dictionary. I needed to use some rule for whether to recurse or not otherwise it would try and walk the properties of things like lists of objects etc. I figure that I'm already using a convention for my model classes, so I could stick to it.
public static RouteValueDictionary ToRouteValueDictionary(this object obj)
{
var Result = new RouteValueDictionary(obj);
// Find any ignored properties
var BindAttribute = (BindAttribute)obj.GetType().GetCustomAttributes(typeof(BindAttribute), true).SingleOrDefault();
var ExcludedProperties = new List<string>();
if (BindAttribute != null)
{
ExcludedProperties.AddRange(BindAttribute.Exclude.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
}
// Remove any ignored properties from the dictionary
foreach (var ExcludedProperty in ExcludedProperties)
{
Result.Remove(ExcludedProperty);
}
// Loop through each property, recursively adding sub-properties that end with "Model" to the dictionary
foreach (var Property in obj.GetType().GetProperties())
{
if (ExcludedProperties.Contains(Property.Name))
{
continue;
}
if (Property.PropertyType.Name.EndsWith("Model"))
{
Result.Remove(Property.Name);
var PropertyValue = Property.GetValue(obj, null);
if (PropertyValue != null)
{
var PropertyDictionary = PropertyValue.ToRouteValueDictionary();
foreach (var Key in PropertyDictionary.Keys)
{
Result.Add(string.Format("{0}.{1}", Property.Name, Key), PropertyDictionary[Key]);
}
}
}
}
return Result;
}
I have the following code for an attribute i'm applying to a class and a property within the class:
public class SerialiseAttribute : Attribute, IAspectProvider, IValidableAnnotation {
public string ApplyToProperty { get; set; }
public string Name { get; set; }
public bool Ignore { get; set; }
bool IValidableAnnotation.CompileTimeValidate(object target) { return true; }
IEnumerable<AspectInstance> IAspectProvider.ProvideAspects(object targetElement) {
var type = targetElement as Type;
if (type != null && !FastSerialisationCacheAttribute.AppliedTo.Contains(type)) {
FastSerialisationCacheAttribute.AppliedTo.Add(type);
yield return new AspectInstance(type, new FastSerialisationCacheAttribute());
}
}
}
This intialises the FastSerialisationCacheAttribute and executes CompileTimeInitialize successfully (it derives from the TypeLevelAspect aspect). However, when I check the IL generated; there is no FastSerialisationCacheAttribute on the type provided, nor at runtime can I find one using reflection.
If I switch out the ProviderAspects function with this code:
IEnumerable<AspectInstance> IAspectProvider.ProvideAspects(object targetElement) {
var type = targetElement as Type;
if (type != null && !FastSerialisationCacheAttribute.AppliedTo.Contains(type)) {
FastSerialisationCacheAttribute.AppliedTo.Add(type);
var constructor = typeof(FastSerialisationCacheAttribute).GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
var objectConstruction = new ObjectConstruction(constructor);
var introduceCacheAspect = new CustomAttributeIntroductionAspect(objectConstruction);
yield return new AspectInstance(type, introduceCacheAspect);
}
}
Then it adds the attribute to IL, but this doesn't initialise the attribute (execute CompileTimeInitialize).
Well, I think you're already really close to a solution in your question. If you want to introduce both aspect and attribute dynamically then you need to return instances of both FastSerialisationCacheAttribute and CustomAttributeIntroductionAspect from ProvideAspects method.
The method IAspectProvider.ProvideAspects is executed after all the previously applied aspect attributes have been read from the assembly. If you introduce another attribute in the second example then it's already too late for it to cause aspect introduction.
In IAspectProvider.ProvideAspects you would normally introduce additional aspects to the target. If you really need to also introduce the actual attribute, then you would use CustomAttributeIntroductionAspect.
Note that adding the attribute is normally not needed for the aspect to work, but I don't know what is the logic in your code.
I am working on a project where I need to queue up a number of property changes. Let say I have:
public class foo
{
string bar { get; set; }
int bar1 { get; set }
}
I want to have some code that looks like:
//Store value set actions in a queue
foo.SetValue(bar, "abc");
foo.SetValue(bar1, 123);
//Preview changes
foreach(Item change in foo.ChangeQueue)
{
Console.Write(change.PropertyName.ToString());
Console.Write(change.Value.ToString());
}
//Apply actions
foo.CommitChanges();
What is the best way to accomplish this?
You can use Dictionary<string,object> as ChangeQueue to store your values.
You can iterate as,
foreach(KeyValuePair<string,object> item in ChangeQueue){
Console.WriteLine(item.Key);// name of property
Console.WriteLine(item.Value); // value of property
}
public void SetValue(string name, object value){
PropertyInfo p = this.GetType().GetProperty(name);
// following convert and raise an exception to preserve type safety
ChangeQueue[name] = Convert.ChangeType(value,p.PropertyType);
}
public void ApplyChanges(){
foreach(KeyValuePair<string,object> item in ChangeQueue){
PropertyInfo p = this.GetType().GetProperty(item.Key);
p.SetValue(this, item.Value, null);
}
}
"Type-safe" version which uses callbacks. This will not automatically remove duplicate-settings. It also does not use reflection and so property-name errors will fail on compilation. This method could be expanded to require a "name" and remove duplicates by using a Dictionary backing (as per Akash's answer) or allow the "setter" to return a value (such as success or failure or the old value, or whatnot).
interface Setter {
void Apply();
}
class Setter<T> : Setter {
public T Data;
public Action<T> SetFn;
public void Apply() {
SetFn(Data);
}
}
List<Setter> changeQueue = new List<Setter>();
void SetValue<T>(Action<T> setFn, T data){
changeQueue.Add(new Setter<T> {
Data = data,
SetFn = setFn,
});
}
void ApplyChanges(){
foreach (var s in changeQueue){
s.Apply();
}
}
// .. later on
SetValue(x => System.Console.WriteLine(x), "hello world!");
ApplyChanges();
This method can also be trivially used "outside" the objects being monitored because all the operations are in potential closures.
Happy coding.