I want to build a caching class with IInterceptionBehavior like describe in this MSDN article and I want to use it like an attribute.
But when I test this out, I have this error: The type "CacheAction" does not have an accessible constructor. I need your help to understand why. The "CacheAction" is the enum I give into the contructor.
Here is the code, the caching class without private methods:
/// <summary>
/// Cache action types.
/// </summary>
public enum CacheAction
{
/// <summary>
/// Add a new item to cache.
/// </summary>
Add,
/// <summary>
/// Remove all associated items from cache for the given domain model.
/// </summary>
Remove
}
[Serializable]
public class CacheAttribute : FilterAttribute, ICache, IInterceptionBehavior
{
private readonly ICache _cache;
[NonSerialized]
private object _syncRoot;
public readonly CacheAction _action;
public CacheAttribute(CacheAction action)
{
_cache = new StaticMemoryCache();
_action = action;
_syncRoot = new object();
}
public IMethodReturn Invoke(IMethodInvocation input,
GetNextInterceptionBehaviorDelegate getNext)
{
if (_action == CacheAction.Add)
{
var cacheKey = BuildCacheKey(input);
// If cache is empty, execute the target method, retrieve the return value and cache it.
if (_cache[cacheKey] == null)
{
lock (_syncRoot)
{
// Execute the target method
IMethodReturn returnVal = getNext()(input, getNext);
// Cache the return value
_cache[cacheKey] = returnVal;
return returnVal;
}
}
// Otherwise, return the cache result
return input.CreateMethodReturn(_cache[cacheKey]);
}
else
{
var typeName = GetTypeName(input.GetType());
lock (_syncRoot)
{
_cache.Remove(typeName);
}
IMethodReturn returnVal = getNext()(input, getNext);
return returnVal;
}
}
Here the code for Unity configuration (look at InterfaceInterceptor call):
container.AddNewExtension<Interception>();
container
//.RegisterType<ICache, CacheAttribute>()
.RegisterType<IDataContextAsync, ApplicationDbContext>(new PerRequestLifetimeManager())
.RegisterType<IRepositoryProvider, RepositoryProvider>(
new PerRequestLifetimeManager(),
new InjectionConstructor(new object[] { new RepositoryFactories() })
)
.RegisterType<IUnitOfWorkAsync, UnitOfWork>(new PerRequestLifetimeManager())
.RegisterType<IRepositoryAsync<Movie>, Repository<Movie>>(
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<CacheAttribute>())
.RegisterType<IMovieService, MovieService>()
.RegisterType<IUnitOfWorkAsync, UnitOfWork>(new PerRequestLifetimeManager());
DependencyResolver.SetResolver(new Microsoft.Practices.Unity.Mvc.UnityDependencyResolver(container));
And here is where I do my test with a repository:
public static class MovieRepository
{
[Cache(CacheAction.Add)]
public static int test(this IRepositoryAsync<Movie> repository)
{
return 1;
}
}
So, need help to understand what I'm missing to get the error: The type "CacheAction" does not have an accessible constructor.
Thank you,
David
Related
public class CacheController
{
public IMemoryCache _memoryCache {get; set;}
public string getCacheMethodOne(string token)
{
string cacheValue = null;
string cacheKey = null;
if (!_memoryCache.TryGetValue<string>("123456", out cacheValue))
{
cacheValue = token;
cacheKey = "123456";
var cacheEntryOptions = new MemoryCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromMinutes(2));
_memoryCache.Set<string>("123456", cacheValue, cacheEntryOptions);
}
return cacheKey;
}
}
Problem with this line of code:
string otp = new
CacheController().getCacheMethodOne(ClientJsonOtp.ToString());
throws exception.
Object reference not set to an instance of an object.
Should i create new instances of IMemorycahce.
If i do so, will it affect the cache. as it may lose the previous cache instance.
try
{
var finalResult = result.Content.ReadAsStringAsync().Result;
var ClientJsonOtp = JsonConvert.DeserializeObject(finalResult);
string otp = new CacheController().getCacheMethodOne(ClientJsonOtp.ToString());
return Json(ClientJsonOtp, JsonRequestBehavior.AllowGet);
}
You need to create one, at least once. Otherwise it will always be null.
You can do that when you call the empty constructor:
public CacheController()
{
this._memoryCache = new // whatever memory cache you choose;
}
You can even better inject it somewhere using dependency injection. The place depends on application type.
But best of all, try to have only once cache. Each time you create one you lose the previous, so you will either try the singleton pattern, or inject using a single instance configuration and let the DI container handle the rest.
An example for the singleton implementation: here
You can access by using:
Cache.Instance.Read(//what)
Here is the cache implementation
using System;
using System.Configuration;
using System.Runtime.Caching;
namespace Client.Project.HelperClasses
{
/// <summary>
/// Thread Safe Singleton Cache Class
/// </summary>
public sealed class Cache
{
private static volatile Cache instance; // Locks var until assignment is complete for double safety
private static MemoryCache memoryCache;
private static object syncRoot = new Object();
private static string settingMemoryCacheName;
private static double settingCacheExpirationTimeInMinutes;
private Cache() { }
/// <summary>
/// Singleton Cache Instance
/// </summary>
public static Cache Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
InitializeInstance();
}
}
}
return instance;
}
}
private static void InitializeInstance()
{
var appSettings = ConfigurationManager.AppSettings;
settingMemoryCacheName = appSettings["MemoryCacheName"];
if (settingMemoryCacheName == null)
throw new Exception("Please enter a name for the cache in app.config, under 'MemoryCacheName'");
if (! Double.TryParse(appSettings["CacheExpirationTimeInMinutes"], out settingCacheExpirationTimeInMinutes))
throw new Exception("Please enter how many minutes the cache should be kept in app.config, under 'CacheExpirationTimeInMinutes'");
instance = new Cache();
memoryCache = new MemoryCache(settingMemoryCacheName);
}
/// <summary>
/// Writes Key Value Pair to Cache
/// </summary>
/// <param name="Key">Key to associate Value with in Cache</param>
/// <param name="Value">Value to be stored in Cache associated with Key</param>
public void Write(string Key, object Value)
{
memoryCache.Add(Key, Value, DateTimeOffset.Now.AddMinutes(settingCacheExpirationTimeInMinutes));
}
/// <summary>
/// Returns Value stored in Cache
/// </summary>
/// <param name="Key"></param>
/// <returns>Value stored in cache</returns>
public object Read(string Key)
{
return memoryCache.Get(Key);
}
/// <summary>
/// Returns Value stored in Cache, null if non existent
/// </summary>
/// <param name="Key"></param>
/// <returns>Value stored in cache</returns>
public object TryRead(string Key)
{
try
{
return memoryCache.Get(Key);
}
catch (Exception)
{
return null;
}
}
}
}
I'v developed a Rules Engine library, called RulesChain, that works perfectly when the rules doesn't need that any dependency to be injected.
The primary goal with this library is to simplify writing business rules in .NET environment based on Rules Design Pattern and Chain of Responsability Pattern to work like ASP.Net Core middlewares works.
When I need to have any dependency injected I get this error:
System.MissingMethodException: 'Constructor on type 'AspNetCoreRulesChainSample.Rules.ShoppingCartRules.IsValidCupomRule' not found.'
What is the problem?
My abstract Rule class needs to receive the next rule to be called on it's constructor. But I can't add the put an specific Rule on constructor because the chain is resolved on RuleChain class
How it Works?
Basically all rules have a ShouldRun method that defines if the run method should be called a Run method that applies the Business Rule. And the Invoke method that is called inside the rule when it needs to call the next rule.
This is the rule with dependency injection that throws an error:
public class IsValidCupomRule : Rule<ApplyDiscountContext>
{
private ISalesRepository _salesRepository;
public IsValidCupomRule(Rule<ApplyDiscountContext> next, ISalesRepository salesRepository) : base(next)
{
_salesRepository = salesRepository;
}
public override ApplyDiscountContext Run(ApplyDiscountContext context)
{
// Gets 7% of discount;
var myDiscount = context.Context.Items.Sum(i => i.Price * 0.07M);
context = _next.Invoke(context) ?? context;
// Only apply first order disccount if the discount applied by the other rules are smaller than this
if (myDiscount > context.DiscountApplied)
{
context.DiscountApplied = myDiscount;
context.DiscountTypeApplied = "Cupom";
}
return context;
}
public override bool ShouldRun(ApplyDiscountContext context)
{
return !string.IsNullOrWhiteSpace(context.Context.CupomCode)
&& context.Context.Items?.Count > 1
&& _salesRepository.IsCupomAvaliable(context.Context.CupomCode);
}
}
A basic rule without dependency is like that.
public class BirthdayDiscountRule : Rule<ApplyDiscountContext>
{
public BirthdayDiscountRule(Rule<ApplyDiscountContext> next) : base(next)
{ }
public override ApplyDiscountContext Run(ApplyDiscountContext context)
{
// Gets 10% of discount;
var birthDayDiscount = context.Context.Items.Sum(i => i.Price * 0.1M);
context = _next.Invoke(context);
// Only apply birthday disccount if the discount applied by the other rules are smaller than this
if (birthDayDiscount > context.DiscountApplied)
{
context.DiscountApplied = birthDayDiscount;
context.DiscountTypeApplied = "Birthday Discount";
}
return context;
}
public override bool ShouldRun(ApplyDiscountContext context)
{
var dayAndMonth = context.ClientBirthday.ToString("ddMM");
var todayDayAndMonth = DateTime.Now.ToString("ddMM");
return dayAndMonth == todayDayAndMonth;
}
}
And the abstract rule is that:
public abstract class Rule<T> : IRule<T>
{
protected readonly Rule<T> _next;
protected Rule(Rule<T> next)
{
_next = next;
}
/// <summary>
/// Valides if the rules should be executed or not
/// </summary>
/// <returns></returns>
public abstract bool ShouldRun(T context);
/// <summary>
/// Executes the rule
/// </summary>
/// <returns></returns>
public abstract T Run(T context);
public virtual T Invoke(T context)
{
if(ShouldRun(context))
return Run(context);
else
return _next != null
? _next.Invoke(context)
: context;
}
}
To create my chain of rules I just need to do this:
public ShoppingCart ApplyDiscountOnShoppingCart(ShoppingCart shoppingCart)
{
// Create the chain
var shoppingCartRuleChain = new RuleChain<ApplyDiscountContext>()
.Use<IsValidCupomRule>()
.Use<BirthdayDiscountRule>()
.Use<FirstOrderDiscountRule>()
.Build();
// Create the chain context
var shoppingCartRuleContext = new ApplyDiscountContext(shoppingCart);
shoppingCartRuleContext.Properties["IsFirstOrder"] = true;
shoppingCartRuleContext.ClientBirthday = DateTime.UtcNow;
// Invoke the RulesChain
shoppingCartRuleContext = shoppingCartRuleChain.Invoke(shoppingCartRuleContext);
// Get data form the Chain result and return a ShoppingCart with new data.
shoppingCart.Discount = shoppingCartRuleContext.DiscountApplied;
shoppingCart.DiscountType = shoppingCartRuleContext.DiscountTypeApplied;
return shoppingCart;
}
The principal point for me here is that I can put any Rule in the .Use<IRule>() call and it permits that the rules does not depends on each other and the chain can be changed without the need of refactoring each rule. I'm doing this on Build() method.
This methos just invert the order of each rule on the chain and creates a new instance of each rule, and adds the last Rule instance as the next Rule of he new Rule.
This is the RuleChain class
public class RuleChain<T> : IRuleChain<T>
{
private readonly IList<Type> _components = new List<Type>();
public IRuleChain<T> Use<TRule>()
{
_components.Add(typeof(TRule));
return this;
}
public IRule<T> Build()
{
IRule<T> app = EndOfChainRule<T>.EndOfChain();
foreach (var component in _components.Reverse())
{
app = (IRule<T>)Activator.CreateInstance(component,app);
}
return app;
}
}
Here is how I instantiate new Rules with the next Rule: app = (IRule<T>)Activator.CreateInstance(component,app);
Other information that may be useful:
This is how I resolve Dependencies on IoC module
public static class Modules
{
public static void AddRepository(this IServiceCollection services)
{
services.AddScoped<ISalesRepository, SalesRepository>();
}
public static void AddRules(this IServiceCollection services)
{
services.AddScoped<IsValidCupomRule>();
services.AddScoped<FirstOrderDiscountRule>();
services.AddScoped<BirthdayDiscountRule>();
services.AddScoped<ShoppingCartRulesChain>();
}
}
My startup.cs Configure is this:
public void ConfigureServices(IServiceCollection services)
{
services.AddRepository();
services.AddRules();
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
Whats my question?
How can I instantiate a new class based on the same Rule<T> class and with dependencies of IServiceCollection?
The RulesChain source code is available at: https://github.com/lutticoelho/RulesChain
This sample source code is available at: https://github.com/lutticoelho/AspNetCoreRulesChainSample
If anyone needs more information about, or to put more code on the question feel free to ask at the comments and I'll provide any changes needed in this question.
Now there is a lot to unpack here. First observation would be with the RuleChain class.
If the intention is to allow for Dependency Injection via constructor injection then the current design of the class will need to be refactored to allow for that.
Since the current design is modeled behind the Asp.Net Core Middleware pipeline, I would suggest using delegates to store and handle the desired invocation.
First define a delegate to handle the rule processing
/// <summary>
/// A function that can process a <see cref="TContext"/> dependent rule.
/// </summary>
/// <typeparam name="TContext"></typeparam>
/// <param name="context"></param>
/// <returns>A task that represents the completion of rule processing</returns>
public delegate Task RuleHandlingDelegate<TContext>(TContext context);
The advantage of using the delegate is that it can be late bound to an actual implementation after all the necessary dependencies have be resolved.
Also note that this generic delegate definition uses Task to allow for asynchronous operations
This does require a change to the IRuleChain<T> definition.
/// <summary>
/// Defines a class that provides the mechanisms to configure an application's rules pipeline execution.
/// </summary>
/// <typeparam name="TContext">The context shared by all rules in the chain</typeparam>
public interface IRuleChain<TContext> {
/// <summary>
/// Adds a rule to the application's request chain.
/// </summary>
/// <returns>The <see cref="IRuleChain{T}"/>.</returns>
IRuleChain<TContext> Use<TRule>();
/// <summary>
/// Builds the delegate used by this application to process rules executions.
/// </summary>
/// <returns>The rules handling delegate.</returns>
RuleHandlingDelegate<TContext> Build();
}
And the implementation.
In order to allow other arguments to be injected into the rule implementation, the chain will need to be able to resolve constructor argument.
public abstract class RuleChain<TContext> : IRuleChain<TContext> {
private readonly Stack<Func<RuleHandlingDelegate<TContext>, RuleHandlingDelegate<TContext>>> components =
new Stack<Func<RuleHandlingDelegate<TContext>, RuleHandlingDelegate<TContext>>>();
private bool built = false;
public RuleHandlingDelegate<TContext> Build() {
if (built) throw new InvalidOperationException("Chain can only be built once");
var next = new RuleHandlingDelegate<TContext>(context => Task.CompletedTask);
while (components.Any()) {
var component = components.Pop();
next = component(next);
}
built = true;
return next;
}
public IRuleChain<TContext> Use<TRule>() {
components.Push(createDelegate<TRule>);
return this;
}
protected abstract object GetService(Type type, params object[] args);
private RuleHandlingDelegate<TContext> createDelegate<TRule>(RuleHandlingDelegate<TContext> next) {
var ruleType = typeof(TRule);
MethodInfo methodInfo = getValidInvokeMethodInfo(ruleType);
//Constructor parameters
object[] constructorArguments = new object[] { next };
object[] dependencies = getDependencies(ruleType, GetService);
if (dependencies.Any())
constructorArguments = constructorArguments.Concat(dependencies).ToArray();
//Create the rule instance using the constructor arguments (including dependencies)
object rule = GetService(ruleType, constructorArguments);
//return the delegate for the rule
return (RuleHandlingDelegate<TContext>)methodInfo
.CreateDelegate(typeof(RuleHandlingDelegate<TContext>), rule);
}
private MethodInfo getValidInvokeMethodInfo(Type type) {
//Must have public method named Invoke or InvokeAsync.
var methodInfo = type.GetMethod("Invoke") ?? type.GetMethod("InvokeAsync");
if (methodInfo == null)
throw new InvalidOperationException("Missing invoke method");
//This method must: Return a Task.
if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType))
throw new InvalidOperationException("invalid invoke return type");
//and accept a first parameter of type TContext.
ParameterInfo[] parameters = methodInfo.GetParameters();
if (parameters.Length != 1 || parameters[0].ParameterType != typeof(TContext))
throw new InvalidOperationException("invalid invoke parameter type");
return methodInfo;
}
private object[] getDependencies(Type middlewareType, Func<Type, object[], object> factory) {
var constructors = middlewareType.GetConstructors().Where(c => c.IsPublic).ToArray();
var constructor = constructors.Length == 1 ? constructors[0]
: constructors.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault();
if (constructor != null) {
var ctorArgsTypes = constructor.GetParameters().Select(p => p.ParameterType).ToArray();
return ctorArgsTypes
.Skip(1) //Skipping first argument since it is suppose to be next delegate
.Select(parameter => factory(parameter, null)) //resolve other parameters
.ToArray();
}
return Array.Empty<object>();
}
}
With this abstract chain, it is now the responsibility of it's implementation to define how to resolve any dependencies.
Following the sample context, that is simple enough. Since using the default DI extension, then the chain should depend on IServiceProvider for types whose arguments are not known and Activator for those with provided constructor arguments.
public class DiscountRuleChain : RuleChain<ApplyDiscountContext> {
private readonly IServiceProvider services;
public DiscountRuleChain(IServiceProvider services) {
this.services = services;
}
protected override object GetService(Type type, params object[] args) =>
args == null || args.Length == 0
? services.GetService(type)
: Activator.CreateInstance(type, args);
}
With all of the above provided so far, there were some changes that allowed for a cleaner design.
Specifically IRule<TContext> and its default implementation.
public interface IRule<TContext> {
Task Invoke(TContext context);
}
public abstract class Rule<TContext> : IRule<TContext> {
protected readonly RuleHandlingDelegate<TContext> next;
protected Rule(RuleHandlingDelegate<TContext> next) {
this.next = next;
}
public abstract Task Invoke(TContext context);
}
Any Context specific rules can now be abstracted to target a specific domain
For example
public abstract class DiscountRule : Rule<ApplyDiscountContext> {
protected DiscountRule(RuleHandlingDelegate<ApplyDiscountContext> next) : base(next) {
}
}
This simplified the implementations specific to discounts in the sample and allowed for dependencies to be injected
IsValidCupomRule
public class IsValidCupomRule : DiscountRule {
private readonly ISalesRepository _salesRepository;
public IsValidCupomRule(RuleHandlingDelegate<ApplyDiscountContext> next, ISalesRepository salesRepository)
: base(next) {
_salesRepository = salesRepository;
}
public override async Task Invoke(ApplyDiscountContext context) {
if (cupomAvailable(context)) {
// Gets 7% of discount;
var myDiscount = context.Context.Items.Sum(i => i.Price * 0.07M);
await next.Invoke(context);
// Only apply discount if the discount applied by the other rules are smaller than this
if (myDiscount > context.DiscountApplied) {
context.DiscountApplied = myDiscount;
context.DiscountTypeApplied = "Cupom";
}
} else
await next(context);
}
private bool cupomAvailable(ApplyDiscountContext context) {
return !string.IsNullOrWhiteSpace(context.Context.CupomCode)
&& context.Context.Items?.Count > 1
&& _salesRepository.IsCupomAvaliable(context.Context.CupomCode);
}
}
FirstOrderDiscountRule
public class FirstOrderDiscountRule : DiscountRule {
public FirstOrderDiscountRule(RuleHandlingDelegate<ApplyDiscountContext> next) : base(next) { }
public override async Task Invoke(ApplyDiscountContext context) {
if (shouldRun(context)) {
// Gets 5% of discount;
var myDiscount = context.Context.Items.Sum(i => i.Price * 0.05M);
await next.Invoke(context);
// Only apply discount if the discount applied by the other rules are smaller than this
if (myDiscount > context.DiscountApplied) {
context.DiscountApplied = myDiscount;
context.DiscountTypeApplied = "First Order Discount";
}
} else
await next.Invoke(context);
}
bool shouldRun(ApplyDiscountContext context) {
return (bool)(context.Properties["IsFirstOrder"] ?? false);
}
}
The following test was used to verify expected behavior of the rules engine.
[TestClass]
public class RulesEngineTests {
[TestMethod]
public async Task Should_Apply_Cupom_Discount() {
//Arrange
var cupomCode = "cupomCode";
var services = new ServiceCollection()
.AddSingleton<ISalesRepository>(sp =>
Mock.Of<ISalesRepository>(_ => _.IsCupomAvaliable(cupomCode) == true)
)
.BuildServiceProvider();
// Create the chain
var shoppingCartRuleChain = new DiscountRuleChain(services)
.Use<IsValidCupomRule>()
.Use<FirstOrderDiscountRule>()
.Build();
ShoppingCart shoppingCart = new ShoppingCart {
CupomCode = cupomCode,
Items = new List<ShoppingCartItem> {
new ShoppingCartItem { Price = 10M },
new ShoppingCartItem { Price = 10M },
}
};
var expectedDiscountType = "Cupom";
var expectedDiscountApplied = 1.40M;
// Create the chain context
var shoppingCartRuleContext = new ApplyDiscountContext(shoppingCart);
shoppingCartRuleContext.Properties["IsFirstOrder"] = true;
shoppingCartRuleContext.ClientBirthday = DateTime.UtcNow;
//Act
await shoppingCartRuleChain.Invoke(shoppingCartRuleContext);
// Get data from the context result and verify new data.
shoppingCart.Discount = shoppingCartRuleContext.DiscountApplied;
shoppingCart.DiscountType = shoppingCartRuleContext.DiscountTypeApplied;
//Assert (using FluentAssertions)
shoppingCart.DiscountType.Should().Be(expectedDiscountType);
shoppingCart.Discount.Should().Be(expectedDiscountApplied);
}
}
Note how the dependency to be injected was mocked to test the expected behavior in isolation.
I'm building a LINQ extension to streamline database access through EF, and part of that process is mapping the data entity to the business entity.
I use a Dictionary<string, int> to decide what navigational properties to include, and to what depth.
Example:
public static class LinqExtensions
{
private static readonly Dictionary<string, int> Dictionary = new Dictionary<string, int>();
/// <summary>
/// Adds the navigational property identified by value to be included in the query and entity mapping, recursing a maximum of depth times.
/// </summary>
/// <param name="value">Navigational Property to add</param>
/// <param name="depth">Desired recursion depth</param>
public static TSource With<TSource>(this TSource source, string value, int depth = 0)
{
Dictionary.Add(value, depth);
return source;
}
/// <summary>
/// Clears the navigational property dictionary
/// </summary>
public static void Reset()
{
Dictionary.Clear();
}
/// <summary>
/// Builds and executes a query, dynamically including desired navigational properties in a asynchronous fashion.
/// The result is then mapped to the provided TResult business entity and returned as a list.
/// </summary>
/// <returns>Null or a list of mapped domain Entities</returns>
public static async Task<IEnumerable<TResult>> BuildQueryAsync<TSource, TResult>(this IQueryable<TSource> dbEntity) where TResult : class, new()
{
var query = dbEntity;
var localDictionary = new Dictionary<string, int>(Dictionary);
Reset();
foreach (var i in localDictionary)
{
query = query.Include(i.Key);
}
List<TSource> result = await (from entity in query select entity).ToListAsync();
return Equals(result, default(TSource)) ? null : result.Select(u => u.BuildEntity(new TResult(), localDictionary));
}
/// <summary>
/// Maps values from sourceEntity to targetEntity, recursing into properties defined in localDictionary.
/// </summary>
public static TTarget BuildEntity<TSource, TTarget>(this TSource sourceEntity, TTarget targetEntity, Dictionary<string, int> localDictionary)
{
return (TTarget)targetEntity.InjectFrom(new SinglePropertyDepthInjection(localDictionary), sourceEntity);
}
}
This lets me access stuff in my repository and services as follows:
public override async Task<IEnumerable<User>> GetAllAsync()
{
return await _context.Users.With("Messages", 1).With("Notifications", 2).BuildQueryAsync<Data.Entities.User, User>();
}
Now i'm well aware that this isn't feasible, due to static properties being shared across all requests.
I know I could easilly add a dictionary as a method parameter, and solving it as such:
public override async Task<IEnumerable<User>> GetAllAsync()
{
var dict = new Dictionary<string, int>();
dict.Add("Messages", 1);
dict.Add("Notifications", 2);
return await _context.Users.BuildQueryAsync<Data.Entities.User, User>(dict);
}
But I was wondering if there is perhaps a more elegant solution, ideally keeping it as part of the LINQ query.
I know there is HttpContext.Current, but since the methods involved are async I'm not sure how good of an idea it is to go back onto the context thread.
Any ideas?
I think CallContext might be what you are looking for.
In combination with the disposable pattern such things can be scoped pretty easy.
public class IncludeScope : IDisposable
{
private const string CallContextKey = "IncludeScopKey";
private object oldValue;
public IncludeScope(IDictionary<string,int> values)
{
this.oldValue = CallContext.GetData(CallContextKey);
this.Includes = new Dictionary<string,int>(values);
CallContext.SetData(CallContextKey, this);
}
public Dictionary<string,int> Includes { get; private set; }
public static IncludeScope Current {
get { return CallContext.GetData(CallContextKey) as IncludeScope; }
}
private bool _disposed;
protected virtual bool IsDisposed
{
get
{
return _disposed;
}
}
~IncludeScope()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed) {
if (disposing) {
CallContext.SetData(CallContextKey, oldValue);
}
_disposed = true;
}
}
}
The scope can be declared like this.
using(var scope = new IncludeScope(new Dictionary<string,int>{{"Message",1}, {"Notifications",2}})){
var query = await GetQueryAsync<User>();
…
}
In any method call within the using the scope can be accessed like this.
private static Task<IQueryable<T>> GetQueryAsync<T>() {
var baseQuery = context.Set<T>();
foreach (var include in IncludeScope.Current.Includes) {
}
}
Please refer to the following code. Using MEF I have created a manager object and a plug-in, which imports the IQueryEngine as it should.
However, when I call the method _queryEngine.Get() in the plugin, I get a MissingMethodException, like the method isn't implemented in the concrete implementation of QueryEngine, however it is implemented. I believe that this has to do with the ManagedElementDTO class, but I am not sure what to do here.
Can anyone shed some light on what is going on?
I have an interface:
public interface IQueryEngine
{
ManagedElementDTO Get();
}
And the implementation:
public class QueryEngine : IQueryEngine
{
public ManagedElementDTO Get()
{
return new ManagedElementDTO();
}
}
This engine is declared in a manager:
[Export]
public class ProviderSupervisor : ISupervisor
{
[Export("QueryEngine")]
private IQueryEngine _queryEngine;
[ImportMany(typeof(IProviderModule))]
private IEnumerable<IProviderModule> _providers;
public ProviderSupervisor(IStore store)
{
_queryEngine = new QueryEngine();
CreateContainer();
}
/// <summary>
/// Creates the composition container and composes the parts.
/// </summary>
/// <returns>The container.</returns>
private CompositionContainer CreateContainer()
{
try
{
var catalog = new AggregateCatalog();
var directory = GetProviderDirectory();
if (directory.Exists)
{
catalog.Catalogs.Add(new DirectoryCatalog(directory.FullName));
}
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
return container;
}
catch (Exception)
{
// TODO: Log Error
throw;
}
}
private static DirectoryInfo GetProviderDirectory()
{
var location = ConfigurationSupervisor.GetInstance().ProviderLocation;
if (!string.IsNullOrWhiteSpace(location))
{
var providerLocation = new DirectoryInfo(Environment.ExpandEnvironmentVariables(location));
if (providerLocation.Exists)
{
return providerLocation;
}
}
// Use the current assembly location as the default.
var exeLocation = new FileInfo(Assembly.GetExecutingAssembly().Location);
return exeLocation.Directory;
}
}
and the plug-in:
[Export(typeof(IProviderModule))]
public class Provider : IProviderModule, IDisposable
{
private IQueryEngine _queryEngine;
#region Properties
/// <summary>
/// Gets or sets the query engine.
/// </summary>
[Import("QueryEngine", typeof(IQueryEngine), RequiredCreationPolicy = CreationPolicy.Shared)]
public IQueryEngine QueryEngine
{
get { return _queryEngine; }
set
{
_queryEngine = value;
}
}
public void InvokeQueryEngine()
{
var item = _queryEngine.Get(); // Exception!
}
}
In order to export your QueryEngine type you should be doing the following
[Export(typeof(IQueryEngine))]
public class QueryEngine : QueryEngine
Now in the plugin class importing it should be as simple as
[Import(typeof(IQueryEngine), RequiredCreationPolicy = CreationPolicy.Shared)]
public IQueryEngine QueryEngine
{
get { return _queryEngine; }
set
{
_queryEngine = value;
}
}
I'm not quite sure what you are attempting to do with the [Export] on the IQueryEngine field. You should be able to delete that entirely
I have a constructor which has a non-interface dependency:
public MainWindowViewModel(IWorkItemProvider workItemProvider, WeekNavigatorViewModel weekNavigator)
I am using the Moq.Contrib automockcontainer. If I try to automock the MainWindowViewModel class, I get an error due to the WeekNavigatorViewModel dependency.
Are there any automocking containers which supports mocking of non-interface types?
As Mark has shown below; yes you can! :-) I replaced the Moq.Contrib AutoMockContainer with the stuff Mark presents in his answer, the only difference is that the auto-generated mocks are registered as singletons, but you can make this configurable. Here is the final solution:
/// <summary>
/// Auto-mocking factory that can create an instance of the
/// class under test and automatically inject mocks for all its dependencies.
/// </summary>
/// <remarks>
/// Mocks interface and class dependencies
/// </remarks>
public class AutoMockContainer
{
readonly IContainer _container;
public AutoMockContainer(MockFactory factory)
{
var builder = new ContainerBuilder();
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
builder.RegisterSource(new MoqRegistrationSource(factory));
_container = builder.Build();
}
/// <summary>
/// Gets or creates a mock for the given type, with
/// the default behavior specified by the factory.
/// </summary>
public Mock<T> GetMock<T>() where T : class
{
return (_container.Resolve<T>() as IMocked<T>).Mock;
}
/// <summary>
/// Creates an instance of a class under test,
/// injecting all necessary dependencies as mocks.
/// </summary>
/// <typeparam name="T">Requested object type.</typeparam>
public T Create<T>() where T : class
{
return _container.Resolve<T>();
}
public T Resolve<T>()
{
return _container.Resolve<T>();
}
/// <summary>
/// Registers and resolves the given service on the container.
/// </summary>
/// <typeparam name="TService">Service</typeparam>
/// <typeparam name="TImplementation">The implementation of the service.</typeparam>
public void Register<TService, TImplementation>()
{
var builder = new ContainerBuilder();
builder.RegisterType<TImplementation>().As<TService>().SingleInstance();
builder.Update(_container);
}
/// <summary>
/// Registers the given service instance on the container.
/// </summary>
/// <typeparam name="TService">Service type.</typeparam>
/// <param name="instance">Service instance.</param>
public void Register<TService>(TService instance)
{
var builder = new ContainerBuilder();
if (instance.GetType().IsClass)
builder.RegisterInstance(instance as object).As<TService>();
else
builder.Register(c => instance).As<TService>();
builder.Update(_container);
}
class MoqRegistrationSource : IRegistrationSource
{
private readonly MockFactory _factory;
private readonly MethodInfo _createMethod;
public MoqRegistrationSource(MockFactory factory)
{
_factory = factory;
_createMethod = factory.GetType().GetMethod("Create", new Type[] { });
}
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
var swt = service as IServiceWithType;
if (swt == null)
{
yield break;
}
if (!swt.ServiceType.IsInterface)
yield break;
var existingReg = registrationAccessor(service);
if (existingReg.Any())
{
yield break;
}
var reg = RegistrationBuilder.ForDelegate((c, p) =>
{
var createMethod = _createMethod.MakeGenericMethod(swt.ServiceType);
return ((Mock)createMethod.Invoke(_factory, null)).Object;
}).As(swt.ServiceType).SingleInstance().CreateRegistration();
yield return reg;
}
public bool IsAdapterForIndividualComponents
{
get { return false; }
}
}
}
You can pretty easily write one yourself if you leverage a DI Container that supports just-in-time resolution of requested types.
I recently wrote a prototype for exactly that purpose using Autofac and Moq, but other containers could be used instead.
Here's the appropriate IRegistrationSource:
public class AutoMockingRegistrationSource : IRegistrationSource
{
private readonly MockFactory mockFactory;
public AutoMockingRegistrationSource()
{
this.mockFactory = new MockFactory(MockBehavior.Default);
this.mockFactory.CallBase = true;
this.mockFactory.DefaultValue = DefaultValue.Mock;
}
public MockFactory MockFactory
{
get { return this.mockFactory; }
}
#region IRegistrationSource Members
public IEnumerable<IComponentRegistration> RegistrationsFor(
Service service,
Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
var swt = service as IServiceWithType;
if (swt == null)
{
yield break;
}
var existingReg = registrationAccessor(service);
if (existingReg.Any())
{
yield break;
}
var reg = RegistrationBuilder.ForDelegate((c, p) =>
{
var createMethod =
typeof(MockFactory).GetMethod("Create", Type.EmptyTypes).MakeGenericMethod(swt.ServiceType);
return ((Mock)createMethod.Invoke(this.MockFactory, null)).Object;
}).As(swt.ServiceType).CreateRegistration();
yield return reg;
}
#endregion
}
You can now set up the container in a unit test like this:
[TestMethod]
public void ContainerCanCreate()
{
// Fixture setup
var builder = new ContainerBuilder();
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
builder.RegisterSource(new AutoMockingRegistrationSource());
var container = builder.Build();
// Exercise system
var result = container.Resolve<MyClass>();
// Verify outcome
Assert.IsNotNull(result);
// Teardown
}
That's all you need to get started.
MyClass is a concrete class with an abstract dependency. Here is the constructor signature:
public MyClass(ISomeInterface some)
Notice that you don't have to use Autofac (or any other DI Container) in your production code.