I want to test whether the if-else statements are executed,
The "if" block returns the item from the dictionary/cache and returns the output, while "else" block adds the input inside the cache and returns an output
An interface of IModifyBehavior with a method Apply
I have this classes:
namespace Decorator
{
using System;
/// <summary>
/// Reverse Behavior
/// </summary>
public class ReverseBehavior : IModifyBehavior
{
/// <summary>
/// Applies the specified value.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>result</returns>
public string Apply(string value)
{
var result = string.Empty;
if (value != null)
{
char[] letters = value.ToCharArray();
Array.Reverse(letters);
result = new string(letters);
}
return result;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// Caching Decorator
/// </summary>
public class CachingDecorator : IModifyBehavior
{
/// <summary>
/// The behavior
/// </summary>
private IModifyBehavior behavior;
public CachingDecorator(IModifyBehavior behavior)
{
if (behavior == null)
{
throw new ArgumentNullException("behavior");
}
this.behavior = behavior;
}
private static Dictionary<string, string> cache = new Dictionary<string, string>();
/// <summary>
/// Applies the specified value.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>
/// value
/// </returns>
public string Apply(string value)
{
////Key = original value, Value = Reversed
var result = string.Empty;
//cache.Add("randel", "lednar");
if(cache.ContainsKey(value))
{
result = cache[value];
}
else
{
result = this.behavior.Apply(value);// = "reversed";
////Note:Add(key,value)
cache.Add(value, result);
}
return result;
}
}
}
Here's my current code for the test, the codes were able to passed the test, but I'm not sure if my implementation was correct:
[TestClass]
public class CachingDecoratorTest
{
private IModifyBehavior behavior;
[TestInitialize]
public void Setup()
{
this.behavior = new CachingDecorator(new ReverseBehavior());
}
[TestCleanup]
public void Teardown()
{
this.behavior = null;
}
[TestMethod]
public void Apply_Cached_ReturnsReversedCachedValue()
{
string actual = "randel";
////store it inside the cache
string cached = this.behavior.Apply(actual);
////call the function again, to test the else block statement
////Implement DRY principle next time
string expected = this.behavior.Apply(actual);
Assert.IsTrue(cached.Equals(expected));
}
[TestMethod]
public void Apply_NotCached_ReturnsReversed()
{
string actual = "randel";
string expected = "lednar";
Assert.AreEqual(expected, this.behavior.Apply(actual));
}
}
Sir/Ma'am your answers would be of great help. Thank you++
First of all I would actually test the two clases in isolation, as proper units.
Below I wrote up how I would test these. For this I'm using NUnit, and Moq (available in Nuget) as a mocking framework. But you can just change the test attributes and use MSTest instead.
For the reverse behavior I'm covering both a regular apply and applying to a null text:
using System;
using System.Linq;
using Decorator;
using NUnit.Framework;
namespace StackOverflow.Tests.HowToTest
{
[TestFixture]
public class ReverseBehaviorTest
{
[Test]
public void Apply()
{
const string someText = "someText";
var target = new ReverseBehavior();
var result = target.Apply(someText);
Assert.AreEqual(someText.Reverse(), result);
}
[Test]
public void Apply_WhenNull()
{
var target = new ReverseBehavior();
var result = target.Apply(null);
Assert.AreEqual(String.Empty, result);
}
}
}
And for the CachingDecorator, the constructor's exception throwing, applying with caching and without:
using System;
using Decorator;
using Moq;
using NUnit.Framework;
namespace StackOverflow.Tests.HowToTest
{
[TestFixture]
public class CachingDecoratorTest
{
[Test]
public void Constructor()
{
Assert.Throws(typeof(ArgumentNullException), () => new CachingDecorator(null));
}
[Test]
public void Apply_NotCached()
{
var internalBehaviorMock = new Mock<IModifyBehavior>();
internalBehaviorMock.Setup(x => x.Apply(It.IsAny<string>())).Returns<string>(y => y);
const string someText = "someText";
var target = new CachingDecorator(internalBehaviorMock.Object);
target.Apply(someText);
internalBehaviorMock.Verify(x => x.Apply(It.IsAny<string>()), Times.Once());
}
[Test]
public void Apply_Cached()
{
var internalBehaviorMock = new Mock<IModifyBehavior>();
internalBehaviorMock.Setup(x => x.Apply(It.IsAny<string>())).Returns<string>(y => y);
const string someOtherText = "someOtherText";
var target = new CachingDecorator(internalBehaviorMock.Object);
target.Apply(someOtherText);
target.Apply(someOtherText);
internalBehaviorMock.Verify(x => x.Apply(It.IsAny<string>()), Times.Once());
}
}
}
The best way would be to use a mocking framework (like Moq, for instance) to create a fake IModifyBehaviour object.
The Apply_NotCached_ReturnsReversed test would then verify that the Apply method of the mock object was called to generate the result. The Apply_Cached_ReturnsReversedCachedValue test would check that the result was returned without calling the Apply method of the mock object.
As it is, you test for the cached case doesn't actually prove that the result came from the cache.
just try to set cache dictionary values in your testcase and check for count after calling Apply(string value) method.
`
public void Apply_Cached_ReturnsReversedCachedValue()
{
Dictionary<string, string> cacheDict = new Dictionary<string, string>() { { "sometext", "txetemos" } };
string str = "sometext";
int dictionaryCountBeforeApply = cacheDict.Count();
//set value to static cache field using reflection, here dictionary count is 1
Type type = typeof(CachingDecorator);
FieldInfo cacheFieldInfo = type.GetField("cache", BindingFlags.NonPublic | BindingFlags.Static);
cacheFieldInfo.SetValue(decorator, cacheDict);
string result = decorator.Apply(str);
int dictionaryCountAfterApply = cacheDict.Count();
Assert.AreEqual(dictionaryCountAfterApply, dictionaryCountBeforeApply);
}
public void Apply_NotCached_ReturnsReversed()
{
Dictionary<string, string> cacheDict = new Dictionary<string, string>() { };
string str = "sometext";
int dictionaryCountBeforeApply = cacheDict.Count();
//set value to static cache field using reflection, here dictionary count is 0
Type type = typeof(CachingDecorator);
FieldInfo cacheFieldInfo = type.GetField("cache", BindingFlags.NonPublic | BindingFlags.Static);
cacheFieldInfo.SetValue(decorator, cacheDict);
string result = decorator.Apply(str);
int dictionaryCountAfterApply = cacheDict.Count();
Assert.AreNotEqual(dictionaryCountAfterApply, dictionaryCountBeforeApply);
}`
Related
I am trying to Mock Redlock
I have the test below
using Moq;
using RedLockNet;
using System;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace RedLock.Tests
{
public class RedLockTests
{
[Fact]
public async Task TestMockingOfRedlock()
{
var redLockFactoryMock = new Mock<IDistributedLockFactory>();
var mock = new MockRedlock();
redLockFactoryMock.Setup(x => x.CreateLockAsync(It.IsAny<string>(),
It.IsAny<TimeSpan>(), It.IsAny<TimeSpan>(),
It.IsAny<TimeSpan>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(mock);
var sut = new TestRedlockHandler(redLockFactoryMock.Object);
var data = new MyEventData();
await sut.Handle(data);
}
}
}
MockRedlock is a simple mock class that implements IRedLock
public class MockRedlock: IRedLock
{
public void Dispose()
{
}
public string Resource { get; }
public string LockId { get; }
public bool IsAcquired => true;
public RedLockStatus Status => RedLockStatus.Acquired;
public RedLockInstanceSummary InstanceSummary => new RedLockInstanceSummary();
public int ExtendCount { get; }
}
await sut.Handle(data); is a call to a seperate event class
I have shown this below. This has been simplified, but using the code below and the test above the null reference error can be reproduced
public class MyEventData
{
public string Id { get; set; }
public MyEventData()
{
Id = Guid.NewGuid().ToString();
}
}
public class TestRedlockHandler
{
private IDistributedLockFactory _redLockFactory;
public TestRedlockHandler(IDistributedLockFactory redLockFactory)
{
_redLockFactory = redLockFactory;
}
public async Task Handle(MyEventData data)
{
var lockexpiry = TimeSpan.FromMinutes(2.5);
var waitspan = TimeSpan.FromMinutes(2);
var retryspan = TimeSpan.FromSeconds(20);
using (var redlock =
await _redLockFactory.CreateLockAsync(data.Id.ToString(), lockexpiry, waitspan, retryspan, null))
{
if (!redlock.IsAcquired)
{
string errorMessage =
$"Did not acquire Lock on Lead {data.Id.ToString()}. Aborting.\n " +
$"Acquired{redlock.InstanceSummary.Acquired} \n " +
$"Error{redlock.InstanceSummary.Error} \n" +
$"Conflicted {redlock.InstanceSummary.Conflicted} \n" +
$"Status {redlock.Status}";
throw new Exception(errorMessage);
}
}
}
}
When I try to call this I expect my object to be returned, but instead I get null
On the line if (!redlock.IsAcquired) redLock is null
What is missing?
The definition of CreateLockAsync
/// <summary>
/// Gets a RedLock using the factory's set of redis endpoints. You should check the IsAcquired property before performing actions.
/// Blocks and retries up to the specified time limits.
/// </summary>
/// <param name="resource">The resource string to lock on. Only one RedLock should be acquired for any given resource at once.</param>
/// <param name="expiryTime">How long the lock should be held for.
/// RedLocks will automatically extend if the process that created the RedLock is still alive and the RedLock hasn't been disposed.</param>
/// <param name="waitTime">How long to block for until a lock can be acquired.</param>
/// <param name="retryTime">How long to wait between retries when trying to acquire a lock.</param>
/// <param name="cancellationToken">CancellationToken to abort waiting for blocking lock.</param>
/// <returns>A RedLock object.</returns>
Task<IRedLock> CreateLockAsync(string resource, TimeSpan expiryTime, TimeSpan waitTime, TimeSpan retryTime, CancellationToken? cancellationToken = null);
requires a nullable CancellationToken
CancellationToken? cancellationToken = null
But the setup of the mock uses
It.IsAny<CancellationToken>() //NOTE CancellationToken instead of CancellationToken?
Because the setup expects the non-nullable struct but when invoked the nullable CancellationToken? is what will be passed even though it is null,
The mock will return null by default because the setup does not match what was actually invoked.
Once the correct type was used the factory was able to return the desired mock
//...
redLockFactoryMock
.Setup(x => x.CreateLockAsync(It.IsAny<string>(),
It.IsAny<TimeSpan>(), It.IsAny<TimeSpan>(),
It.IsAny<TimeSpan>(), It.IsAny<CancellationToken?>()))
.ReturnsAsync(mock);
//...
I need to be able to resolve a (string) path to a property of a class, like WPF binding does.
So something like "MyProperty.MySubProperty.MyList[2].FinalProperty".
I do not need to subscribe to changes, I just need to resolve it once to get the value.
Is there any code I can reuse of the WPF framework, or anything else that already exists?
I need to be able to resolve a (string) path to a property of a class, like WPF binding does. So something like "MyProperty.MySubProperty.MyList[2].FinalProperty". I do not need to subscribe to changes, I just need to resolve it once to get the value.
It is totally possible to get the value of any path like that. Without knowing the values I put something together that might be able to help.
I'm not an expert at reflection, and it has no error handling at all so you'll need to modify and extend it if satisfies your need.
One thing to note, I couldn't figure out how to resolve the path without a object reference ( the StartClass start = new StartClass(); at the beginning). I'll leave that as an exercise for the reader.
class Program
{
public static void Main()
{
StartClass start = new StartClass();
string path = "MyProperty.MySubProperty.MyList[2].FinalProperty";
string[] props = path.Split('.');
var propertyValue = GetPropertyValue(start, props[0]);
for (int i = 1; i < props.Length; i++)
{
ref string prop = ref props[i];
// check to see if the property is an indexed property
if (prop.Contains("[") && prop.Contains("]"))
{
// split MyList[2] into MyList 2]
string[] split = prop.Split("[");
// get the value of MyList
propertyValue = GetPropertyValue(propertyValue, split[0]);
// get the number in 2]
string rawIndex = split[1].Replace("]", "");
// parse the number to an actual number
if (int.TryParse(rawIndex, out int index))
{
// make sure the property is an enumerable, wouldn't make much sense to use an index on it if it wasn't
if (propertyValue is IEnumerable enumerable)
{
propertyValue = enumerable.Cast<object>().ElementAt(index);
}
else
{
throw new NotSupportedException("Attempted to index non-enumerable object");
}
}
else
{
throw new NotSupportedException("Index isn't integer, ranges supported at this time.");
}
}
else
{
// if the property wasn't an indexed property, just get the next value of the next property
propertyValue = GetPropertyValue(propertyValue, prop);
}
}
Console.WriteLine(propertyValue);
// outputs: 12
}
public static object GetPropertyValue(object property, string PropertyName)
{
var propertyInfo = property.GetType().GetProperty(PropertyName);
return propertyInfo.GetValue(property);
}
}
public class StartClass
{
public A MyProperty { get; set; } = new();
}
public class A
{
public B MySubProperty { get; set; } = new B();
}
public class B
{
public List<C> MyList { get; set; } = new List<C>() {
new C(),
new C(),
new C(),
};
}
public class C
{
public int FinalProperty { get; set; } = 12;
}
If you need to parse completely 100% equivalent to the binding, then it is better to use a simple proxy with a binding.
Here is my simple implementation of such a proxy.
In it, in addition to getting the property value, you can also listen to its change, find out if the binding is set and in what state it is.
using System;
using System.Windows;
using System.Windows.Data;
namespace Proxy
{
/// <summary> Provides a <see cref="DependencyObject"/> proxy with
/// one property and an event notifying about its change. </summary>
public class ProxyDO : DependencyObject
{
/// <summary> Property for setting external bindings. </summary>
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
// Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(nameof(Value), typeof(object), typeof(ProxyDO), new PropertyMetadata(null));
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
ValueChanged?.Invoke(this, e);
}
/// <summary> An event that occurs when the value of any
/// <see cref="DependencyProperty"/> of this object changes.</summary>
public event EventHandler<DependencyPropertyChangedEventArgs> ValueChanged;
/// <summary> Returns <see langword="true"/> if the property value <see cref="Value"/> is not set.</summary>
public bool IsUnsetValue => Equals(ReadLocalValue(ValueProperty), DependencyProperty.UnsetValue);
/// <summary> Clears all <see cref="DependencyProperty"/> this <see cref="ProxyDO"/>.</summary>
public void Reset()
{
LocalValueEnumerator locallySetProperties = GetLocalValueEnumerator();
while (locallySetProperties.MoveNext())
{
DependencyProperty propertyToClear = locallySetProperties.Current.Property;
if (!propertyToClear.ReadOnly)
{
ClearValue(propertyToClear);
}
}
}
/// <summary> <see langword="true"/> if the property <see cref="Value"/> has Binding.</summary>
public bool IsValueBinding => BindingOperations.GetBindingExpressionBase(this, ValueProperty) != null;
/// <summary> <see langword="true"/> if the property <see cref="Value"/> has a binding
/// and it is in the state <see cref="BindingStatus.Active"/>.</summary>
public bool IsActiveValueBinding
{
get
{
var exp = BindingOperations.GetBindingExpressionBase(this, ValueProperty);
if (exp == null)
return false;
var status = exp.Status;
return status == BindingStatus.Active;
}
}
/// <summary>Setting the Binding to the Property <see cref="Value"/>.</summary>
/// <param name="binding">The binding to be assigned to the property.</param>
public void SetValueBinding(BindingBase binding)
=> BindingOperations.SetBinding(this, ValueProperty, binding);
}
}
An example of using a proxy:
ProxyDO proxy;
public void MainMetod()
{
// Create Proxy.
proxy = new ProxyDO();
//An example of adding a wiretapping method, if necessary.
proxy.ValueChanged += OnValueChanged;
// Setting Binding.
string propertyPath = "All string";
proxy.SetValueBinding(new Binding(propertyPath));
object currentValue = proxy.Value;
}
private void OnValueChanged(object sender, DependencyPropertyChangedEventArgs e)
{
//Listening code
}
P.S. Shown in a very simplified form.
When creating a binding, for correct operation, you must specify other parameters in addition to the path.
At least Source is an object in which, according to the specified property path, this source property will be searched for.
I'll try to make this as clear as possible.
A Plugin architecture using reflection and 2 Attributes and an abstract class:
PluginEntryAttribute(Targets.Assembly, typeof(MyPlugin))
PluginImplAttribute(Targets.Class, ...)
abstract class Plugin
Commands are routed to a plugin via an interface and a delegate:
Ex: public delegate TTarget Command<TTarget>(object obj);
Using extension methods with Command<> as the target, a CommandRouter executes the delegate on the correct target interface:
Ex:
public static TResult Execute<TTarget, TResult>(this Command<TTarget> target, Func<TTarget, TResult> func) {
return CommandRouter.Default.Execute(func);
}
Putting this together, I have a class hard-coded with the command delegates like so:
public class Repositories {
public static Command<IDispatchingRepository> Dispatching = (o) => { return (IDispatchingRepository)o; };
public static Command<IPositioningRepository> Positioning = (o) => { return (IPositioningRepository)o; };
public static Command<ISchedulingRepository> Scheduling = (o) => { return (ISchedulingRepository)o; };
public static Command<IHistographyRepository> Histography = (o) => { return (IHistographyRepository)o; };
}
When an object wants to query from the repository, practical execution looks like this:
var expBob = Dispatching.Execute(repo => repo.AddCustomer("Bob"));
var actBob = Dispatching.Execute(repo => repo.GetCustomer("Bob"));
My question is this: how can I create such a class as Repositories dynamically from the plugins?
I can see the possibility that another attribute might be necessary. Something along the lines of:
[RoutedCommand("Dispatching", typeof(IDispatchingRepository)")]
public Command<IDispatchingRepository> Dispatching = (o) => { return (IDispatchingRepository)o; };
This is just an idea, but I'm at a loss as to how I'd still create a dynamic menu of sorts like the Repositories class.
For completeness, the CommandRouter.Execute(...) method and related Dictionary<,>:
private readonly Dictionary<Type, object> commandTargets;
internal TResult Execute<TTarget, TResult>(Func<TTarget, TResult> func) {
var result = default(TResult);
if (commandTargets.TryGetValue(typeof(TTarget), out object target)) {
result = func((TTarget)target);
}
return result;
}
OK, i am not sure if this is what you are looking for. I am assuming that each plugin contains field of the following definition:
public Command<T> {Name} = (o) => { return (T)o; };
example from code provided by you:
public Command<IDispatchingRepository> Dispatching = (o) => { return (IDispatchingRepository)o; };
One way to dynamically create class in .NET Core is by using the Microsoft.CodeAnalysis.CSharp nuget - this is Roslyn.
The result is compiled assembly with class called DynamicRepositories having all command fields from all plugins from all loaded dlls into the current AppDomain represented as static public fields.
The code has 3 main components: DynamicRepositoriesBuildInfo class, GetDynamicRepositoriesBuildInfo method and LoadDynamicRepositortyIntoAppDomain method.
DynamicRepositoriesBuildInfo - information for the command fields from the plugins and all assemblies needed to be loaded during the dynamic complication. This will be the assemblies which defines the Command type and the generic arguments of the Command type (ex: IDispatchingRepository)
GetDynamicRepositoriesBuildInfo method - creates DynamicRepositoriesBuildInfo using reflection by scanning loaded assemblies for the PluginEntryAttribute and PluginImplAttribute.
LoadDynamicRepositortyIntoAppDomain method - DynamicRepositoriesBuildInfo it creates assembly called DynamicRepository.dll with single public class App.Dynamic.DynamicRepositories
Here is the code
public class DynamicRepositoriesBuildInfo
{
public IReadOnlyCollection<Assembly> ReferencesAssemblies { get; }
public IReadOnlyCollection<FieldInfo> PluginCommandFieldInfos { get; }
public DynamicRepositoriesBuildInfo(
IReadOnlyCollection<Assembly> referencesAssemblies,
IReadOnlyCollection<FieldInfo> pluginCommandFieldInfos)
{
this.ReferencesAssemblies = referencesAssemblies;
this.PluginCommandFieldInfos = pluginCommandFieldInfos;
}
}
private static DynamicRepositoriesBuildInfo GetDynamicRepositoriesBuildInfo()
{
var pluginCommandProperties = (from a in AppDomain.CurrentDomain.GetAssemblies()
let entryAttr = a.GetCustomAttribute<PluginEntryAttribute>()
where entryAttr != null
from t in a.DefinedTypes
where t == entryAttr.PluginType
from p in t.GetFields(BindingFlags.Public | BindingFlags.Instance)
where p.FieldType.GetGenericTypeDefinition() == typeof(Command<>)
select p).ToList();
var referenceAssemblies = pluginCommandProperties
.Select(x => x.DeclaringType.Assembly)
.ToList();
referenceAssemblies.AddRange(
pluginCommandProperties
.SelectMany(x => x.FieldType.GetGenericArguments())
.Select(x => x.Assembly)
);
var buildInfo = new DynamicRepositoriesBuildInfo(
pluginCommandFieldInfos: pluginCommandProperties,
referencesAssemblies: referenceAssemblies.Distinct().ToList()
);
return buildInfo;
}
private static Assembly LoadDynamicRepositortyIntoAppDomain()
{
var buildInfo = GetDynamicRepositoriesBuildInfo();
var csScriptBuilder = new StringBuilder();
csScriptBuilder.AppendLine("using System;");
csScriptBuilder.AppendLine("namespace App.Dynamic");
csScriptBuilder.AppendLine("{");
csScriptBuilder.AppendLine(" public class DynamicRepositories");
csScriptBuilder.AppendLine(" {");
foreach (var commandFieldInfo in buildInfo.PluginCommandFieldInfos)
{
var commandNamespaceStr = commandFieldInfo.FieldType.Namespace;
var commandTypeStr = commandFieldInfo.FieldType.Name.Split('`')[0];
var commandGenericArgStr = commandFieldInfo.FieldType.GetGenericArguments().Single().FullName;
var commandFieldNameStr = commandFieldInfo.Name;
csScriptBuilder.AppendLine($"public {commandNamespaceStr}.{commandTypeStr}<{commandGenericArgStr}> {commandFieldNameStr} => (o) => ({commandGenericArgStr})o;");
}
csScriptBuilder.AppendLine(" }");
csScriptBuilder.AppendLine("}");
var sourceText = SourceText.From(csScriptBuilder.ToString());
var parseOpt = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3);
var syntaxTree = SyntaxFactory.ParseSyntaxTree(sourceText, parseOpt);
var references = new List<MetadataReference>
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(System.Runtime.AssemblyTargetedPatchBandAttribute).Assembly.Location),
};
references.AddRange(buildInfo.ReferencesAssemblies.Select(a => MetadataReference.CreateFromFile(a.Location)));
var compileOpt = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary,
optimizationLevel: OptimizationLevel.Release,
assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default);
var compilation = CSharpCompilation.Create(
"DynamicRepository.dll",
new[] { syntaxTree },
references: references,
options: compileOpt);
using (var memStream = new MemoryStream())
{
var result = compilation.Emit(memStream);
if (result.Success)
{
var assembly = AppDomain.CurrentDomain.Load(memStream.ToArray());
return assembly;
}
else
{
throw new ArgumentException();
}
}
}
This is how to execute the code
var assembly = LoadDynamicRepositortyIntoAppDomain();
var type = assembly.GetType("App.Dynamic.DynamicRepositories");
The type variable represents the compiled class which has all the plugin commands as public static fields. You are loosing all type safety once you start using dynamic code compilation / building. If you need to execute some code from the type variable you will need reflection.
So if you have
PluginA
{
public Command<IDispatchingRepository> Dispatching= (o) => ....
}
PluginB
{
public Command<IDispatchingRepository> Scheduling = (o) => ....
}
the dynamically create type will look like this
public class DynamicRepositories
{
public static Command<IDispatchingRepository> Dispatching= (o) => ....
public static Command<IDispatchingRepository> Scheduling = (o) => ....
}
Here's another take, which does not require building code dynamically.
I'm assuming the following code for the plugin framework. Note that I did not make any assumptions regarding the abstract Plugin class, because I had no further information.
#region Plugin Framework
public delegate TTarget Command<out TTarget>(object obj);
/// <summary>
/// Abstract base class for plugins.
/// </summary>
public abstract class Plugin
{
}
#endregion
Next, here are two sample plugins. Note the DynamicTarget custom attributes, which I will describe in the next step.
#region Sample Plugin: ICustomerRepository
/// <summary>
/// Sample model class, representing a customer.
/// </summary>
public class Customer
{
public Customer(string name)
{
Name = name;
}
public string Name { get; }
}
/// <summary>
/// Sample target interface.
/// </summary>
public interface ICustomerRepository
{
Customer AddCustomer(string name);
Customer GetCustomer(string name);
}
/// <summary>
/// Sample plugin.
/// </summary>
[DynamicTarget(typeof(ICustomerRepository))]
public class CustomerRepositoryPlugin : Plugin, ICustomerRepository
{
private readonly Dictionary<string, Customer> _customers = new Dictionary<string, Customer>();
public Customer AddCustomer(string name)
{
var customer = new Customer(name);
_customers[name] = customer;
return customer;
}
public Customer GetCustomer(string name)
{
return _customers[name];
}
}
#endregion
#region Sample Plugin: IProductRepository
/// <summary>
/// Sample model class, representing a product.
/// </summary>
public class Product
{
public Product(string name)
{
Name = name;
}
public string Name { get; }
}
/// <summary>
/// Sample target interface.
/// </summary>
public interface IProductRepository
{
Product AddProduct(string name);
Product GetProduct(string name);
}
/// <summary>
/// Sample plugin.
/// </summary>
[DynamicTarget(typeof(IProductRepository))]
public class ProductRepositoryPlugin : Plugin, IProductRepository
{
private readonly Dictionary<string, Product> _products = new Dictionary<string, Product>();
public Product AddProduct(string name)
{
var product = new Product(name);
_products[name] = product;
return product;
}
public Product GetProduct(string name)
{
return _products[name];
}
}
#endregion
Here's what your static Repositories class would look like with the two sample plugins:
#region Static Repositories Example Class from Question
public static class Repositories
{
public static readonly Command<ICustomerRepository> CustomerRepositoryCommand = o => (ICustomerRepository) o;
public static readonly Command<IProductRepository> ProductRepositoryCommand = o => (IProductRepository) o;
}
#endregion
To begin the actual answer to your question here's the custom attribute used to mark the plugins. This custom attribute has been used on the two example plugins shown above.
/// <summary>
/// Marks a plugin as the target of a <see cref="Command{TTarget}" />, specifying
/// the type to be registered with the <see cref="DynamicCommands" />.
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public class DynamicTargetAttribute : Attribute
{
public DynamicTargetAttribute(Type type)
{
Type = type;
}
public Type Type { get; }
}
The custom attribute is parsed in the RegisterDynamicTargets(Assembly) of the following DynamicRepository class to identify the plugins and the types (e.g., ICustomerRepository) to be registered. The targets are registered with the CommandRouter shown below.
/// <summary>
/// A dynamic command repository.
/// </summary>
public static class DynamicCommands
{
/// <summary>
/// For all assemblies in the current domain, registers all targets marked with the
/// <see cref="DynamicTargetAttribute" />.
/// </summary>
public static void RegisterDynamicTargets()
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
RegisterDynamicTargets(assembly);
}
}
/// <summary>
/// For the given <see cref="Assembly" />, registers all targets marked with the
/// <see cref="DynamicTargetAttribute" />.
/// </summary>
/// <param name="assembly"></param>
public static void RegisterDynamicTargets(Assembly assembly)
{
IEnumerable<Type> types = assembly
.GetTypes()
.Where(type => type.CustomAttributes
.Any(ca => ca.AttributeType == typeof(DynamicTargetAttribute)));
foreach (Type type in types)
{
// Note: This assumes that we simply instantiate an instance upon registration.
// You might have a different convention with your plugins (e.g., they might be
// singletons accessed via an Instance or Default property). Therefore, you
// might have to change this.
object target = Activator.CreateInstance(type);
IEnumerable<CustomAttributeData> customAttributes = type.CustomAttributes
.Where(ca => ca.AttributeType == typeof(DynamicTargetAttribute));
foreach (CustomAttributeData customAttribute in customAttributes)
{
CustomAttributeTypedArgument argument = customAttribute.ConstructorArguments.First();
CommandRouter.Default.RegisterTarget((Type) argument.Value, target);
}
}
}
/// <summary>
/// Registers the given target.
/// </summary>
/// <typeparam name="TTarget">The type of the target.</typeparam>
/// <param name="target">The target.</param>
public static void RegisterTarget<TTarget>(TTarget target)
{
CommandRouter.Default.RegisterTarget(target);
}
/// <summary>
/// Gets the <see cref="Command{TTarget}" /> for the given <typeparamref name="TTarget" />
/// type.
/// </summary>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <returns>The <see cref="Command{TTarget}" />.</returns>
public static Command<TTarget> Get<TTarget>()
{
return obj => (TTarget) obj;
}
/// <summary>
/// Extension method used to help dispatch the command.
/// </summary>
/// <typeparam name="TTarget">The type of the target.</typeparam>
/// <typeparam name="TResult">The type of the result of the function invoked on the target.</typeparam>
/// <param name="_">The <see cref="Command{TTarget}" />.</param>
/// <param name="func">The function invoked on the target.</param>
/// <returns>The result of the function invoked on the target.</returns>
public static TResult Execute<TTarget, TResult>(this Command<TTarget> _, Func<TTarget, TResult> func)
{
return CommandRouter.Default.Execute(func);
}
}
Instead of dynamically creating properties, the above utility class offers a simple Command<TTarget> Get<TTarget>() method, with which you can create the Command<TTarget> instance, which is then used in the Execute extension method. The latter method finally delegates to the CommandRouter shown next.
/// <summary>
/// Command router used to dispatch commands to targets.
/// </summary>
public class CommandRouter
{
public static readonly CommandRouter Default = new CommandRouter();
private readonly Dictionary<Type, object> _commandTargets = new Dictionary<Type, object>();
/// <summary>
/// Registers a target.
/// </summary>
/// <typeparam name="TTarget">The type of the target instance.</typeparam>
/// <param name="target">The target instance.</param>
public void RegisterTarget<TTarget>(TTarget target)
{
_commandTargets[typeof(TTarget)] = target;
}
/// <summary>
/// Registers a target instance by <see cref="Type" />.
/// </summary>
/// <param name="type">The <see cref="Type" /> of the target.</param>
/// <param name="target">The target instance.</param>
public void RegisterTarget(Type type, object target)
{
_commandTargets[type] = target;
}
internal TResult Execute<TTarget, TResult>(Func<TTarget, TResult> func)
{
var result = default(TResult);
if (_commandTargets.TryGetValue(typeof(TTarget), out object target))
{
result = func((TTarget)target);
}
return result;
}
}
#endregion
Finally, here are a few unit tests showing how the above classes work.
#region Unit Tests
public class DynamicCommandTests
{
[Fact]
public void TestUsingStaticRepository_StaticDeclaration_Success()
{
ICustomerRepository customerRepository = new CustomerRepositoryPlugin();
CommandRouter.Default.RegisterTarget(customerRepository);
Command<ICustomerRepository> command = Repositories.CustomerRepositoryCommand;
Customer expected = command.Execute(repo => repo.AddCustomer("Bob"));
Customer actual = command.Execute(repo => repo.GetCustomer("Bob"));
Assert.Equal(expected, actual);
Assert.Equal("Bob", actual.Name);
}
[Fact]
public void TestUsingDynamicRepository_ManualRegistration_Success()
{
ICustomerRepository customerRepository = new CustomerRepositoryPlugin();
DynamicCommands.RegisterTarget(customerRepository);
Command<ICustomerRepository> command = DynamicCommands.Get<ICustomerRepository>();
Customer expected = command.Execute(repo => repo.AddCustomer("Bob"));
Customer actual = command.Execute(repo => repo.GetCustomer("Bob"));
Assert.Equal(expected, actual);
Assert.Equal("Bob", actual.Name);
}
[Fact]
public void TestUsingDynamicRepository_DynamicRegistration_Success()
{
// Register all plugins, i.e., CustomerRepositoryPlugin and ProductRepositoryPlugin
// in this test case.
DynamicCommands.RegisterDynamicTargets();
// Invoke ICustomerRepository methods on CustomerRepositoryPlugin target.
Command<ICustomerRepository> customerCommand = DynamicCommands.Get<ICustomerRepository>();
Customer expectedBob = customerCommand.Execute(repo => repo.AddCustomer("Bob"));
Customer actualBob = customerCommand.Execute(repo => repo.GetCustomer("Bob"));
Assert.Equal(expectedBob, actualBob);
Assert.Equal("Bob", actualBob.Name);
// Invoke IProductRepository methods on ProductRepositoryPlugin target.
Command<IProductRepository> productCommand = DynamicCommands.Get<IProductRepository>();
Product expectedHammer = productCommand.Execute(repo => repo.AddProduct("Hammer"));
Product actualHammer = productCommand.Execute(repo => repo.GetProduct("Hammer"));
Assert.Equal(expectedHammer, actualHammer);
Assert.Equal("Hammer", actualHammer.Name);
}
}
#endregion
You can find the whole implementation here.
I have a class LanguagePopupMessage which is used all over the application (and external libraries). If this class is constructed it fetches the namespace where it's created and adds a suffix to be unique.
The Question is: How can get all LanguagePopupMessage definitions including the fieldname parameter?
Im using structuremap in my application. It's also scanning all libraries at startup, so maybe there is a possiblity how to automaticate it. 👀
using System;
using System.Diagnostics;
namespace ConsoleApp1
{
/// <summary>
/// Creates the namespace for a popup window and has an additional flag for the caption
/// </summary>
public class LanguagePopupMessage
{
public string Namespace { get; }
public string Caption => $"{Namespace}Caption";
public LanguagePopupMessage(string fieldName)
{
if(string.IsNullOrEmpty(fieldName))
throw new ArgumentNullException(nameof(fieldName));
if (_GetNamespace() is Type type)
{
Namespace = $"{type}.{fieldName}";
}
else
{
throw new InvalidOperationException("could not fetch the namespace");
}
}
private Type _GetNamespace()
{
StackTrace st = new StackTrace();
foreach (var sf in st.GetFrames())
{
var type = sf.GetMethod().DeclaringType;
if (type != GetType())
{
return type;
}
}
return null;
}
public override string ToString()
{
return $"Namespace '{Namespace}' Caption '{Caption}'";
}
}
class Program
{
//ConsoleApp1.Program.PopupMessage.ConfigNotLoaded
//ConsoleApp1.Program.PopupMessage.ConfigNotLoadedCaption
private static readonly LanguagePopupMessage _CONFIG_NOT_LOADED_POPUP_MESSAGE = new LanguagePopupMessage("ConfigNotLoaded");
static void Main(string[] args)
{
Console.ReadKey();
}
}
}
namespace ConsoleApp1.Subfolder
{
public class SubfolderClass
{
/// <summary>
/// ConsoleApp1.Subfolder.SubfolderClass.FooMessage
/// ConsoleApp1.Subfolder.SubfolderClass.FooMessageCaption
/// </summary>
public static readonly LanguagePopupMessage Message = new LanguagePopupMessage("FooMessage");
}
}
I made a custom IRegistrationConvention - FindAllLanguagePopupMessages for structuremap. During runtime a new container scans all libraries -> all Types if there are any FieldInfo of type LanguagePopupMessage and adding it into a collection.
To get better performance, I made an Attribute - ContainsTranslationDefinition to filter the classes.
Sourcecode
public class ContainsTranslationDefinition : Attribute
{ }
/// <summary>
/// Creates the namespace for a popup window and has an additional flag for the caption
/// </summary>
public class LanguagePopupMessage
{
public string Namespace { get; }
public string Caption => $"{Namespace}Caption";
public LanguagePopupMessage(string fieldName)
{
if(string.IsNullOrEmpty(fieldName))
throw new ArgumentNullException(nameof(fieldName));
if (_GetNamespace() is Type type)
{
Namespace = $"{type}.{fieldName}";
}
else
{
throw new InvalidOperationException("could not fetch the namespace");
}
}
private Type _GetNamespace()
{
StackTrace st = new StackTrace();
foreach (var sf in st.GetFrames())
{
var type = sf.GetMethod().DeclaringType;
if (type != GetType())
{
return type;
}
}
return null;
}
public override string ToString()
{
return $"Namespace '{Namespace}' Caption '{Caption}'";
}
}
/// <summary>
/// Add <see cref="LanguagePopupMessage"/> into the <see cref="Container.Model"/> type lifecycle
/// </summary>
public class FindAllLanguagePopupMessages : IRegistrationConvention
{
private readonly ILifecycle _Lifecycle = new UniquePerRequestLifecycle();
public void ScanTypes(TypeSet types, Registry registry)
{
List<LanguagePopupMessage> dec = new List<LanguagePopupMessage>();
foreach (Type type in types.AllTypes())
{
if (!Attribute.IsDefined(type, typeof(ContainsTranslationDefinition)))
{
continue;
}
_FindConfigDeclarations(type, dec);
}
foreach (LanguagePopupMessage languagePopupMessage in dec)
{
Console.WriteLine($"{languagePopupMessage}");
}
}
private static void _FindConfigDeclarations(Type type, List<LanguagePopupMessage> declarations)
{
var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy);
declarations.AddRange(fields
.Where(info => info.IsInitOnly && typeof(LanguagePopupMessage).IsAssignableFrom(info.FieldType))
.Select(info => (LanguagePopupMessage)info.GetValue(null)));
// find all nested class types and run method recursively
foreach (var nestedType in type.GetNestedTypes(BindingFlags.Public))
{
_FindConfigDeclarations(nestedType, declarations);
}
}
}
[ContainsTranslationDefinition]
public class TestClass
{
private static readonly LanguagePopupMessage _CONFIG_1 = new LanguagePopupMessage("ConfigNotLoaded1");
private static readonly LanguagePopupMessage _CONFIG_2 = new LanguagePopupMessage("ConfigNotLoaded2");
}
[ContainsTranslationDefinition]
public class Program
{
//ConsoleApp1.Program.PopupMessage.ConfigNotLoaded
//ConsoleApp1.Program.PopupMessage.ConfigNotLoadedCaption
private static readonly LanguagePopupMessage _CONFIG_NOT_LOADED_POPUP_MESSAGE = new LanguagePopupMessage("ConfigNotLoaded3");
static void Main(string[] args)
{
// Create container and tell where to look for depencies
IContainer container = new Container(c => c.Scan(scanner =>
{
scanner.TheCallingAssembly();
scanner.WithDefaultConventions();
scanner.AssembliesFromApplicationBaseDirectory();
scanner.With(new FindAllLanguagePopupMessages());
}));
Console.ReadKey();
}
}
Preview
I'm building an app in .NET and C#, and I'd like to cache some of the results by using attributes/annotations instead of explicit code in the method.
I'd like a method signature that looks a bit like this:
[Cache, timeToLive=60]
String getName(string id, string location)
It should make a hash based on the inputs, and use that as the key for the result.
Naturally, there'd be some config file telling it how to actually put in memcached, local dictionary or something.
Do you know of such a framework?
I'd even be interested in one for Java as well
With CacheHandler in Microsoft Enterprise Library you can easily achieve this.
For instance:
[CacheHandler(0, 30, 0)]
public Object GetData(Object input)
{
}
would make all calls to that method cached for 30 minutes. All invocations gets a unique cache-key based on the input data and method name so if you call the method twice with different input it doesn't get cached but if you call it >1 times within the timout interval with the same input then the method only gets executed once.
I've added some extra features to Microsoft's code:
My modified version looks like this:
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Web;
using System.Web.Caching;
using System.Web.UI;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.Unity.InterceptionExtension;
namespace Middleware.Cache
{
/// <summary>
/// An <see cref="ICallHandler"/> that implements caching of the return values of
/// methods. This handler stores the return value in the ASP.NET cache or the Items object of the current request.
/// </summary>
[ConfigurationElementType(typeof (CacheHandler)), Synchronization]
public class CacheHandler : ICallHandler
{
/// <summary>
/// The default expiration time for the cached entries: 5 minutes
/// </summary>
public static readonly TimeSpan DefaultExpirationTime = new TimeSpan(0, 5, 0);
private readonly object cachedData;
private readonly DefaultCacheKeyGenerator keyGenerator;
private readonly bool storeOnlyForThisRequest = true;
private TimeSpan expirationTime;
private GetNextHandlerDelegate getNext;
private IMethodInvocation input;
public CacheHandler(TimeSpan expirationTime, bool storeOnlyForThisRequest)
{
keyGenerator = new DefaultCacheKeyGenerator();
this.expirationTime = expirationTime;
this.storeOnlyForThisRequest = storeOnlyForThisRequest;
}
/// <summary>
/// This constructor is used when we wrap cached data in a CacheHandler so that
/// we can reload the object after it has been removed from the cache.
/// </summary>
/// <param name="expirationTime"></param>
/// <param name="storeOnlyForThisRequest"></param>
/// <param name="input"></param>
/// <param name="getNext"></param>
/// <param name="cachedData"></param>
public CacheHandler(TimeSpan expirationTime, bool storeOnlyForThisRequest,
IMethodInvocation input, GetNextHandlerDelegate getNext,
object cachedData)
: this(expirationTime, storeOnlyForThisRequest)
{
this.input = input;
this.getNext = getNext;
this.cachedData = cachedData;
}
/// <summary>
/// Gets or sets the expiration time for cache data.
/// </summary>
/// <value>The expiration time.</value>
public TimeSpan ExpirationTime
{
get { return expirationTime; }
set { expirationTime = value; }
}
#region ICallHandler Members
/// <summary>
/// Implements the caching behavior of this handler.
/// </summary>
/// <param name="input"><see cref="IMethodInvocation"/> object describing the current call.</param>
/// <param name="getNext">delegate used to get the next handler in the current pipeline.</param>
/// <returns>Return value from target method, or cached result if previous inputs have been seen.</returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
lock (input.MethodBase)
{
this.input = input;
this.getNext = getNext;
return loadUsingCache();
}
}
public int Order
{
get { return 0; }
set { }
}
#endregion
private IMethodReturn loadUsingCache()
{
//We need to synchronize calls to the CacheHandler on method level
//to prevent duplicate calls to methods that could be cached.
lock (input.MethodBase)
{
if (TargetMethodReturnsVoid(input) || HttpContext.Current == null)
{
return getNext()(input, getNext);
}
var inputs = new object[input.Inputs.Count];
for (int i = 0; i < inputs.Length; ++i)
{
inputs[i] = input.Inputs[i];
}
string cacheKey = keyGenerator.CreateCacheKey(input.MethodBase, inputs);
object cachedResult = getCachedResult(cacheKey);
if (cachedResult == null)
{
var stopWatch = Stopwatch.StartNew();
var realReturn = getNext()(input, getNext);
stopWatch.Stop();
if (realReturn.Exception == null && realReturn.ReturnValue != null)
{
AddToCache(cacheKey, realReturn.ReturnValue);
}
return realReturn;
}
var cachedReturn = input.CreateMethodReturn(cachedResult, input.Arguments);
return cachedReturn;
}
}
private object getCachedResult(string cacheKey)
{
//When the method uses input that is not serializable
//we cannot create a cache key and can therefore not
//cache the data.
if (cacheKey == null)
{
return null;
}
object cachedValue = !storeOnlyForThisRequest ? HttpRuntime.Cache.Get(cacheKey) : HttpContext.Current.Items[cacheKey];
var cachedValueCast = cachedValue as CacheHandler;
if (cachedValueCast != null)
{
//This is an object that is reloaded when it is being removed.
//It is therefore wrapped in a CacheHandler-object and we must
//unwrap it before returning it.
return cachedValueCast.cachedData;
}
return cachedValue;
}
private static bool TargetMethodReturnsVoid(IMethodInvocation input)
{
var targetMethod = input.MethodBase as MethodInfo;
return targetMethod != null && targetMethod.ReturnType == typeof (void);
}
private void AddToCache(string key, object valueToCache)
{
if (key == null)
{
//When the method uses input that is not serializable
//we cannot create a cache key and can therefore not
//cache the data.
return;
}
if (!storeOnlyForThisRequest)
{
HttpRuntime.Cache.Insert(
key,
valueToCache,
null,
System.Web.Caching.Cache.NoAbsoluteExpiration,
expirationTime,
CacheItemPriority.Normal, null);
}
else
{
HttpContext.Current.Items[key] = valueToCache;
}
}
}
/// <summary>
/// This interface describes classes that can be used to generate cache key strings
/// for the <see cref="CacheHandler"/>.
/// </summary>
public interface ICacheKeyGenerator
{
/// <summary>
/// Creates a cache key for the given method and set of input arguments.
/// </summary>
/// <param name="method">Method being called.</param>
/// <param name="inputs">Input arguments.</param>
/// <returns>A (hopefully) unique string to be used as a cache key.</returns>
string CreateCacheKey(MethodBase method, object[] inputs);
}
/// <summary>
/// The default <see cref="ICacheKeyGenerator"/> used by the <see cref="CacheHandler"/>.
/// </summary>
public class DefaultCacheKeyGenerator : ICacheKeyGenerator
{
private readonly LosFormatter serializer = new LosFormatter(false, "");
#region ICacheKeyGenerator Members
/// <summary>
/// Create a cache key for the given method and set of input arguments.
/// </summary>
/// <param name="method">Method being called.</param>
/// <param name="inputs">Input arguments.</param>
/// <returns>A (hopefully) unique string to be used as a cache key.</returns>
public string CreateCacheKey(MethodBase method, params object[] inputs)
{
try
{
var sb = new StringBuilder();
if (method.DeclaringType != null)
{
sb.Append(method.DeclaringType.FullName);
}
sb.Append(':');
sb.Append(method.Name);
TextWriter writer = new StringWriter(sb);
if (inputs != null)
{
foreach (var input in inputs)
{
sb.Append(':');
if (input != null)
{
//Diffrerent instances of DateTime which represents the same value
//sometimes serialize differently due to some internal variables which are different.
//We therefore serialize it using Ticks instead. instead.
var inputDateTime = input as DateTime?;
if (inputDateTime.HasValue)
{
sb.Append(inputDateTime.Value.Ticks);
}
else
{
//Serialize the input and write it to the key StringBuilder.
serializer.Serialize(writer, input);
}
}
}
}
return sb.ToString();
}
catch
{
//Something went wrong when generating the key (probably an input-value was not serializble.
//Return a null key.
return null;
}
}
#endregion
}
}
Microsoft deserves most credit for this code. We've only added stuff like caching at request level instead of across requests (more useful than you might think) and fixed some bugs (e.g. equal DateTime-objects serializing to different values).
To do exactly what you are describing, i.e. writing
public class MyClass {
[Cache, timeToLive=60]
string getName(string id, string location){
return ExpensiveCall(id, location);
}
}
// ...
MyClass c = new MyClass();
string name = c.getName("id", "location");
string name_again = c.getName("id", "location");
and having only one invocation of the expensive call and without needing to wrap the class with some other code (f.x. CacheHandler<MyClass> c = new CacheHandler<MyClass>(new MyClass());) you need to look into an Aspect Oriented Programming framework. Those usually work by rewriting the byte-code, so you need to add another step to your compilation process - but you gain a lot of power in the process. There are many AOP-frameworks, but PostSharp for .NET and AspectJ are among the most popular. You can easily Google how to use those to add the caching-aspect you want.