当前位置: 首页 > news >正文

asp.net webapi 结合Autofac实现程序集动态注入(framework版本)

背景

  1. FX版本:4.5.2

Nuget
Autofac:4.2.1
Autofac.WebApi2:4.2.0
log4net:2.0.15

项目结构
在这里插入图片描述

代码

IUniversalService

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IUniversalService
{
    public interface ISendMsg
    {
        /// <summary>
        /// 发送消息接口
        /// </summary>
        /// <param name="msg"></param>
        string Send(object msg);
    }
}

UniversalServiceTest

using IUniversalService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace UniversalServiceTest
{
    public class SendMsg : ISendMsg
    {
        public string Send(object msg)
        {
            return("消息发送被调用了..."+msg);
        }
    }
}

UniversalGateway

using Autofac;
using System.IO;
using System;
using System.Reflection;
using System.Web.Http;
using System.Web.Mvc;
using IUniversalService;
using System.Linq;
using Autofac.Integration.WebApi;
using Autofac.Core;

public class AutofacConfig
{
    /// <summary>
    /// 负责调用autofac框架实现业务逻辑层和数据仓储层程序集中的类型对象的创建
    /// 负责创建MVC控制器类的对象(调用控制器中的有参构造函数),接管DefaultControllerFactory的工作
    /// </summary>
    public static void Register()
    {

        var builder = new ContainerBuilder();

        // Get your HttpConfiguration.
        var config = GlobalConfiguration.Configuration;

        // Register your Web API controllers.
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

        // OPTIONAL: Register the Autofac filter provider.
        builder.RegisterWebApiFilterProvider(config);

        // OPTIONAL: Register the Autofac model binder provider.
        builder.RegisterWebApiModelBinderProvider();

      

        //一次性注册所有实现了IDependency接口的类
        Type baseType = typeof(ISendMsg);
        Assembly[] assemblies =
            Directory.GetFiles(AppDomain.CurrentDomain.RelativeSearchPath + "\\Plugs", "*.dll").Select(Assembly.LoadFrom).ToArray();
        builder.RegisterAssemblyTypes(assemblies)
               .Where(type => baseType.IsAssignableFrom(type) && !type.IsAbstract)
               .AsSelf().AsImplementedInterfaces().PropertiesAutowired()
               .InstancePerLifetimeScope();

        // RegisterType方式:
        //builder.RegisterType<SendMsg>().As<ISendMsg>().InstancePerRequest(); ;

        // Set the dependency resolver to be Autofac.
        var container = builder.Build();
        config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
    }

}

注意:由于我使用到了不同的文件夹来存储定制软件的dll,需要在web.config或者app.config里面进行如下配置

web.config

    <assemblyBinding>
      ...
      <!--<publisherPolicy apply="yes" />这句不要也是可以的-->
      <probing privatePath="Plugs;Plugs/2" />
    </assemblyBinding>

WebApi通用配置项

项目结构图
在这里插入图片描述

ApiResultAttribute.cs


using Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web;
using System.Web.Http.Filters;
using System.Web.Mvc;

namespace Common
{
    public class ApiResultAttribute : System.Web.Http.Filters.ActionFilterAttribute
    {
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            // 不包裹返回值
            var noPackage = actionExecutedContext.ActionContext.ActionDescriptor.GetCustomAttributes<NoPackageResult>();
            if (!noPackage.Any())
            {
                ApiResultModel result = new ApiResultModel();
                //先捕获API内部的异常,无论代码能否完整执行,客户端都能得到正确的响应格式
                if (actionExecutedContext.Exception != null)
                {
                    throw actionExecutedContext.Exception;
                    //result.StatusCode = System.Net.HttpStatusCode.InternalServerError;
                    //result.IsSuccess = false;
                    //result.ErrorMessage = actionExecutedContext.Exception.Message;
                }
                else
                {
                    // 取得由 API 返回的状态代码
                    result.StatusCode = actionExecutedContext.ActionContext.Response.StatusCode;
                    var a = actionExecutedContext.ActionContext.Response.Content.ReadAsAsync<object>();
                    if (!a.IsFaulted)
                    {
                        // 取得由 API 返回的资料
                        result.Data = actionExecutedContext.ActionContext.Response.Content.ReadAsAsync<object>().Result;
                    }
                    //请求是否成功 
                    result.IsSuccess = actionExecutedContext.ActionContext.Response.IsSuccessStatusCode;
                }
                //结果转为自定义消息格式
                HttpResponseMessage httpResponseMessage = JsonHelper.toJson(result);

                // 重新封装回传格式 
                actionExecutedContext.Response = httpResponseMessage;
            }
        }
    }
}

WebApiConfig.cs

using Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

namespace UniversalGateway
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服务

            // Web API 路由
            config.MapHttpAttributeRoutes();
            config.Filters.Add(new ApiResultAttribute());//重新包装结果 
            config.Filters.Add(new ExceptionFilter());//重新包装异常处理过滤器

            config.Routes.MapHttpRoute(
name: "DefaultApi2",
routeTemplate: "api/{controller}/{action}",
defaults: new { action = "Index" }
);

            //config.Routes.MapHttpRoute(
            //    name: "DefaultApi",
            //    routeTemplate: "api/{controller}/{id}",
            //    defaults: new { id = RouteParameter.Optional }
            //);
        }
    }
}

调整内容在这里插入图片描述

ExceptionFilter.cs



using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http.Filters;

namespace Common
{
    /// <summary>
    /// 全局异常过滤器 
    /// </summary>
    /// <!-- 2019-8-22 16:18:10   添加 -->
    public class ExceptionFilter : System.Web.Http.Filters.IExceptionFilter
    {
        public bool AllowMultiple => true;

        public Task ExecuteExceptionFilterAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
        {
            var ex = actionExecutedContext.Exception.InnerException ?? actionExecutedContext.Exception;
            return Task.Run(() =>
            {
                //异常记录日志到本地 2019-8-28 13:55:45 添加
                //Common.LogHelpter.AddLog(ex.ToString());
                LogHelper.ErrorLog(ex);//写入错误日志
                string msg = ex.Message;
                ApiResultModel result = new ApiResultModel();
                result.IsSuccess = false;
                result.StatusCode = System.Net.HttpStatusCode.OK;
                result.ErrorMessage = msg;
                //结果转为自定义消息格式
                HttpResponseMessage httpResponseMessage = JsonHelper.toJson(result);

                // 重新封装回传格式 
                actionExecutedContext.Response = httpResponseMessage;
            });
        }

    }

}

ApiResultModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;

namespace Common
{
    /// <summary>
    /// 返回类型
    /// </summary>
    public class ApiResultModel
    {
        private HttpStatusCode statusCode;
        private object data;
        private string errorMessage;
        private bool isSuccess;

        /// <summary>
        /// 状态代码
        /// </summary>
        public HttpStatusCode StatusCode
        {
            get { return statusCode; }
            set { statusCode = value; }
        }

        /// <summary>
        /// 返回的数据
        /// </summary>
        public object Data
        {
            get { return data; }
            set { data = value; }
        }

        /// <summary>
        /// 错误消息
        /// </summary>
        public string ErrorMessage
        {
            get { return errorMessage; }
            set { errorMessage = value; }
        }

        /// <summary>
        /// 是否成功
        /// </summary>
        public bool IsSuccess
        {
            get { return isSuccess; }
            set { isSuccess = value; }
        }
    }
}

JsonHelper.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Script.Serialization;

namespace Common
{
    public class JsonHelper
    {

        public static HttpResponseMessage toJson(Object obj)
        {
            String str;
            if (obj is String || obj is Char)//如果是字符串或字符直接返回
            {
                str = obj.ToString();
            }
            else//否则序列为json字串
            {
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                str = serializer.Serialize(obj);
            }
            HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(str, Encoding.GetEncoding("UTF-8"), "application/json") };
            return result;
        }
    }
}

LogHelper.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;

namespace Common
{
    public class LogHelper
    {
        #region
        /// <summary>
        /// 记录普通日志
        /// </summary>
        /// <param name="data"></param>
        public static void Info(string data)
        {
            log4net.ILog log = log4net.LogManager.GetLogger("loginfo");
            Task.Run(() => log.Info(data));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="msg"></param>
        public static void ErrorLog(object msg)
        {
            log4net.ILog log = log4net.LogManager.GetLogger("logerror");
            Task.Run(() => log.Error(msg));   //异步
            // Task.Factory.StartNew(() =>log.Error(msg));//  这种异步也可以
            //log.Error(msg);    //这种也行跟你需要,性能越好,越强大,我还是使用异步方式
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ex"></param>
        public static void ErrorLog(Exception ex)
        {
            log4net.ILog log = log4net.LogManager.GetLogger("logerror");
            Task.Run(() => log.Error(ex.Message.ToString() + "/r/n" + ex.Source.ToString() + "/r/n" + ex.TargetSite.ToString() + "/r/n" + ex.StackTrace.ToString()));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="ex"></param>
        public static void ErrorLog(object msg, Exception ex)
        {
            log4net.ILog log = log4net.LogManager.GetLogger("logerror");
            if (ex != null)
            {
                Task.Run(() => log.Error(msg, ex));   //异步
            }
            else
            {
                Task.Run(() => log.Error(msg));   //异步
            }
        }
        #endregion
    }
}

NoPackageResult .cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Common
{
    public class NoPackageResult : Attribute
    {

    }
}

log4net.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.5.2" />
    <httpRuntime targetFramework="4.5.2" />
  </system.web>

  <configSections>
    <!--添加配置节点-->
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>

  <log4net>

    <!--Info 日志-->
    <appender name="InfoAppender" type="log4net.Appender.RollingFileAppender">
      <file value="App_Data\\Logs\\" />
      <appendToFile value="true" />
      <rollingStyle value="Composite" />
      <datePattern value="yyyy-MM-dd\\'info.log'" />
      <staticLogFileName value="false" />
      <param name="MaxSizeRollBackups" value="100"/>
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <param name="Encoding" value="utf-8" />
      <maximumFileSize value="5MB"/>
      <param name="PreserveLogFileNameExtension" value="true"/>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%newline %nDATE:   %date %nTHREAD: [%thread] %n%message %newline %n" />
      </layout>
    </appender>

    <!--Debug 日志-->
    <appender name="DebugAppender" type="log4net.Appender.RollingFileAppender">
      <file value="App_Data\\Logs\\" />
      <appendToFile value="true" />
      <rollingStyle value="Composite" />
      <datePattern value="yyyy-MM-dd\\'debug.log'" />
      <staticLogFileName value="false" />
      <param name="MaxSizeRollBackups" value="100" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <param name="Encoding" value="utf-8" />
      <maximumFileSize value="5MB"/>
      <param name="PreserveLogFileNameExtension" value="true"/>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%newline %nDATE:   %date %nTHREAD: [%thread] %n%message %newline %n" />
      </layout>
    </appender>

    <!--Warn 日志-->
    <appender name="WarnAppender" type="log4net.Appender.RollingFileAppender">
      <file value="App_Data\\Logs\\" />
      <appendToFile value="true" />
      <rollingStyle value="Composite" />
      <datePattern value="yyyy-MM-dd\\'warn.log'" />
      <staticLogFileName value="false" />
      <param name="MaxSizeRollBackups" value="100" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <param name="Encoding" value="utf-8" />
      <maximumFileSize value="5MB"/>
      <param name="PreserveLogFileNameExtension" value="true"/>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%newline %nDATE:   %date %nTHREAD: [%thread] %n%message %newline %n" />
      </layout>
    </appender>

    <!--Error 日志-->
    <appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
      <file value="App_Data\\Logs\\" />
      <appendToFile value="true" />
      <rollingStyle value="Composite" />
      <datePattern value="yyyy-MM-dd\\'error.log'" />
      <staticLogFileName value="false" />
      <param name="MaxSizeRollBackups" value="100" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <param name="Encoding" value="utf-8" />
      <maximumFileSize value="5MB"/>
      <param name="PreserveLogFileNameExtension" value="true"/>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%newline %nDATE:   %date %nTHREAD: [%thread] level: %-5level %n%message %newline %n" />
      </layout>
    </appender>

    <logger name="logerror">
      <level value="ERROR" />
      <appender-ref ref="ErrorAppender" />
    </logger>
    <logger name="logwarn">
      <level value="WARN" />
      <appender-ref ref="WarnAppender" />
    </logger>
    <logger name="loginfo">
      <level value="INFO" />
      <appender-ref ref="InfoAppender" />
    </logger>
    <logger name="logdebug">
      <level value="DEBUG" />
      <appender-ref ref="DebugAppender" />
    </logger>
    <logger name="logmonitor">
      <level value="Monitor" />
      <appender-ref ref="MonitorAppender" />
    </logger>
    <logger name="logsocketsend">
      <level value="INFO" />
      <appender-ref ref="SocketSendAppender" />
    </logger>
    <logger name="logsocketrec">
      <level value="INFO" />
      <appender-ref ref="SocketRecAppender" />
    </logger>
    <logger name="logweather">
      <level value="INFO" />
      <appender-ref ref="WeatherAppender" />
    </logger>
    <logger name="logcheckin">
      <level value="INFO" />
      <appender-ref ref="CheckInAppender" />
    </logger>
  </log4net>
</configuration>



AssemblyInfo.cs 重点就是最后一行代码

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// 有关程序集的常规信息是通过以下项进行控制的
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("UniversalGateway")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("UniversalGateway")]
[assembly: AssemblyCopyright("版权所有(C)  2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// 将 ComVisible 设置为 false 将使此程序集中的类型
// 对 COM 组件不可见。如果需要
// COM,在该类型上将 ComVisible 属性设置为 true。
[assembly: ComVisible(false)]

// 如果此项目向 COM 公开,则下列 GUID 用于 typelib 的 ID
[assembly: Guid("a948378f-b639-48e6-a6de-d52c915c9f96")]

// 程序集的版本信息由下列四个值组成:
//
//      主版本
//      次版本
//      内部版本号
//      修订号
//
// 你可以指定所有值,也可以让修订版本和内部版本号采用默认值,
// 方法是按如下所示使用 "*":
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]

相关文章:

  • 如何选择合适的进销存管理软件?这几点你需要知道
  • 今日踩坑Maven:omitted for duplicate
  • 时至今日“性能优化”为何依旧成为大厂高工必修
  • 使用谷歌浏览器 devtools 调试node项目
  • 猿创征文 | H5 API之web存储、拖拽事件以及跨文档通信
  • 【数据结构与算法】第六篇:红黑树
  • [Power Query] 分组依据
  • Scala系列从入门到精通(三)
  • 项目框架:登录跳转页面
  • 【毕业设计】视频多目标跟踪系统 - 深度学习 机器视觉
  • Deformable detr源码分析
  • 阿里巴巴Java方向面试题汇总(含答案)
  • (利用IDEA+Maven)定制属于自己的jar包
  • OpenCV dnn模块 分类模型Resnet50 OpenCV dnn模块部署 .onnx模型
  • MySQL入门 - 数据分组之 group by
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • 【剑指offer】让抽象问题具体化
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • flutter的key在widget list的作用以及必要性
  • Hibernate最全面试题
  • java架构面试锦集:开源框架+并发+数据结构+大企必备面试题
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • Magento 1.x 中文订单打印乱码
  • MySQL QA
  • Python十分钟制作属于你自己的个性logo
  • 包装类对象
  • - 概述 - 《设计模式(极简c++版)》
  • 前端代码风格自动化系列(二)之Commitlint
  • 深入浅出Node.js
  • 用Canvas画一棵二叉树
  • 在Docker Swarm上部署Apache Storm:第1部分
  • AI算硅基生命吗,为什么?
  • FaaS 的简单实践
  • ​LeetCode解法汇总1276. 不浪费原料的汉堡制作方案
  • #WEB前端(HTML属性)
  • (二)WCF的Binding模型
  • (附源码)springboot高校宿舍交电费系统 毕业设计031552
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (没学懂,待填坑)【动态规划】数位动态规划
  • **python多态
  • .NET CORE 第一节 创建基本的 asp.net core
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .NET 解决重复提交问题
  • .net 设置默认首页
  • .NET 使用配置文件
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • .Net(C#)自定义WinForm控件之小结篇
  • .NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)...
  • .NET正则基础之——正则委托
  • .NET中的Exception处理(C#)
  • .net专家(高海东的专栏)
  • .vimrc php,修改home目录下的.vimrc文件,vim配置php高亮显示
  • @ConditionalOnProperty注解使用说明
  • []指针