• 让MEF插上AOP的翅膀


    1. 什么是MEF

      Git:https://github.com/MicrosoftArchive/mef

      MEF也是一款ioc框架,貌似历史比较悠久了。

      这里有一篇.net阵容里面主流ioc比较。

      https://www.cnblogs.com/liping13599168/archive/2011/07/17/2108734.html

       

    2. AOP

      引用百度。

      在软件业,AOPAspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOPOOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

    3. 背景

      线上有个报表项目,最近监控发现有个报表查询比较频繁,导致db压力大,现需要对查询频次较多的报表进行缓存。

       

    4. 代码实现

      Nugget 引用Castle.Core

      1自定义ExportProved

    public class AOPExportProvider : ExportProvider, IDisposable

    {

    private CatalogExportProvider _exportProvider;

     

    public AOPExportProvider(Func<ComposablePartCatalog> catalogResolver)

    {

    _exportProvider = new CatalogExportProvider(catalogResolver(),true);

     

    //support recomposition

    _exportProvider.ExportsChanged += (s, e) => OnExportsChanged(e);

    _exportProvider.ExportsChanging += (s, e) => OnExportsChanging(e);

    }

     

     

    public ExportProvider SourceProvider

    {

    get

    {

    return _exportProvider.SourceProvider;

    }

    set

    {

    _exportProvider.SourceProvider = value;

    }

    }

     

     

    protected override IEnumerable<Export> GetExportsCore(

    ImportDefinition definition, AtomicComposition atomicComposition)

    {

    IEnumerable<Export> exports = _exportProvider.GetExports(definition, atomicComposition);

    return exports.Select(export => new Export(export.Definition, () => GetValue(export)));

    }

     

    private object GetValue(Export innerExport)

    {

    var value = innerExport.Value;

    IInterceptor[] attribs = value.GetType().GetCustomAttributes(typeof(IInterceptor), true).Cast<IInterceptor>().ToArray();

    if (attribs.Length == 0)

    return value;

    ProxyGenerator generator = new ProxyGenerator();

    object proxy = generator.CreateClassProxy(value.GetType(), attribs);

     

    PropertyInfo[] propertyInfo= value.GetType().GetProperties();

    Type proxyType = proxy.GetType().BaseType;

    foreach (var item in propertyInfo)

    {

    PropertyInfo property = proxyType.GetProperty(item.Name);

    if (property == null) continue;

    property.SetValue(proxy, item.GetValue(value,null),null);

    }

    return proxy;

    }

     

     

    public void Dispose()

    {

    _exportProvider.Dispose();

    }

    }

     

    2 在web启动的时候 指定自定义exportprovide

    public static class MefConfig

    {

    public static void RegisterMef()

    {

    var container = ConfigureContainer();

    ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));

    var dependencyResolver = System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver;

    }

     

    private static CompositionContainer ConfigureContainer()

    {

    Func<ComposablePartCatalog> catalogResolver = () =>

    {

     

    AggregateCatalog catalog = new AggregateCatalog();

    catalog.Catalogs.Add(new DirectoryCatalog(AppDomain.CurrentDomain.SetupInformation.PrivateBinPath, "Mw*.dll"));

    return catalog;

    };

    AOPExportProvider provider = new AOPExportProvider(catalogResolver);

    CompositionContainer container = new CompositionContainer(provider);

    provider.SourceProvider = container;

    AppDomain.CurrentDomain.SetData("Container", container);

    return container;

    }

    }

    3 实现Interceptor

    [Export(typeof(IInterceptor))]

    public class CacheInterceptor : Attribute, IInterceptor

    {

    private ICache _cacheProvider;

    public CacheInterceptor(){

    _cacheProvider = ((CompositionContainer)AppDomain.CurrentDomain.GetData("Container")).GetExportedValue<ICache>();

    }

    private char _linkChar = ':';

    public void Intercept(IInvocation invocation)

    {

    var qCachingAttribute = this.GetQCachingAttributeInfo(invocation.MethodInvocationTarget ?? invocation.Method);

    if (qCachingAttribute != null)

    {

    ProceedCaching(invocation, qCachingAttribute);

    }

    else

    {

    invocation.Proceed();

    }

    }

    private QCachingAttribute GetQCachingAttributeInfo(MethodInfo method)

    {

    return method.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(QCachingAttribute)) as QCachingAttribute;

    }

    private void ProceedCaching(IInvocation invocation, QCachingAttribute attribute)

    {

    var cacheKey = attribute.Key;

    if(string.IsNullOrEmpty(cacheKey))

    cacheKey= GenerateCacheKey(invocation);

     

    var cacheValue = _cacheProvider.Get(cacheKey, x => { return null; });

    if (cacheValue != null)

    {

    invocation.ReturnValue = cacheValue;

    return;

    }

     

    invocation.Proceed();

     

    if (!string.IsNullOrWhiteSpace(cacheKey))

    {

    _cacheProvider.Set(cacheKey, invocation.ReturnValue, TimeSpan.FromSeconds(attribute.AbsoluteExpiration));

    }

    }

    private string GenerateCacheKey(IInvocation invocation)

    {

    var typeName = invocation.TargetType.Name;

    var methodName = invocation.Method.Name;

    var methodArguments = this.FormatArgumentsToPartOfCacheKey(invocation.Arguments);

     

    return this.GenerateCacheKey(typeName, methodName, methodArguments);

    }

    //拼接缓存的键

    private string GenerateCacheKey(string typeName, string methodName, IList<string> parameters)

    {

    var builder = new StringBuilder();

     

    builder.Append(typeName);

    builder.Append(_linkChar);

     

    builder.Append(methodName);

    builder.Append(_linkChar);

     

    foreach (var param in parameters)

    {

    builder.Append(param);

    builder.Append(_linkChar);

    }

     

    return builder.ToString().TrimEnd(_linkChar);

    }

     

    private IList<string> FormatArgumentsToPartOfCacheKey(IList<object> methodArguments, int maxCount = 5)

    {

    return methodArguments.Select(this.GetArgumentValue).Take(maxCount).ToList();

    }

    //处理方法的参数,可根据情况自行调整

    private string GetArgumentValue(object arg)

    {

    if (arg is int || arg is long || arg is string)

    return arg.ToString();

     

    if (arg is DateTime)

    return ((DateTime)arg).ToString("yyyyMMddHHmmss");

     

    if (arg is IQCachable)

    return ((IQCachable)arg).CacheKey;

     

    return null;

    }

    }

    4 定义拦截Attribute

    [AttributeUsage(AttributeTargets.Method, Inherited = true)]

    public class QCachingAttribute: Attribute

    {

    public int AbsoluteExpiration { get; set; } = 30;

    public string Key { get; set; }

    }

    }

    5配置使用Interceptor

    [Export(typeof(ICompanyDaily))]

    [CacheInterceptor]

    public class CompanyDaily : ICompanyDaily

    {

    [Import]

    public ItbshopRepository _shopRepository { get; set; }

    [QCaching(AbsoluteExpiration =60*60*8)]

    public virtual DataTable GetSalesDetailStatistics(DateTime sellDateBegin, DateTime sellDateEnd, string sShopGUID, string mAreaId, int classify, string types)

    {

    string beginDate = sellDateBegin.ToString("yyyy-MM-dd");

    string endDate = sellDateEnd.ToString("yyyy-MM-dd");

    try

    {

    //dosomething

    return dtChart;

    }

    catch (Exception exp)

    {

    throw exp;

    }

    }

    Ps:拦截的方法必须是virtual

  • 相关阅读:
    处理SVN的提交代码冲突
    Oracle对表解锁的操作
    Eclipse 安装反编译插件jadclipse
    如何由jdk的安装版本改成非安装版本
    ASP.NET Web API与Rest web api(一)
    使用C#发送正文带图片邮件
    Silverlight页面通过继承扩展实现
    九度 1347:孤岛连通工程(最小生成树)
    九度 1209:最小邮票数(多重背包)
    利用栈将中缀表达式转化成后缀表达式
  • 原文地址:https://www.cnblogs.com/youngerliu/p/8006620.html
Copyright © 2020-2023  润新知