TinyFrame升级之十:WCF Rest Service注入IOC的心

摘要:
所以这里我使用WCFRestfulService来完成。这里我们需要创建一个新的WCFRestServiceApplication项目:然后在该项目中,我们删除了原始的示例文件并添加了一个QDServiceCs类,并将其设置为Partial模式,以便于多用户协作开发。路线登记完成后,我们将把Autofac整合到项目中。有两个dll需要集成:Autofac是主dll,Autofac.Integration。Wcf是专门为Wcf注射设计的扩展。安装Autofac。集成。Wcf,我们可以使用命令InstallPackageAutofac。Wcf-版本3.0.0-projectTinyFrame。WebService。因为Autofac。集成。Wcf3.0.0需要Autofac 3.0.0及更高版本,我们使用的Autofac版本是3.3.0,我们使用Autofac。集成。此处为Wcf 3.0.0版。

由于在实际开发中,Silverlight需要调用WebService完成数据的获取,由于之前我们一直采用古老的ASMX方式,生成的代理类不仅难以维护,而且自身没有提供APM模式的调用方式,导致在Sinverlight中实现线程同步,非常的困难。所以这里我采用了WCF Restful Service来完成。

这里我们需要新建一个WCF Rest Service Application项目:

image

然后在项目中,我们删掉原有的示例文件,添加一个QDService.cs类,并设为Partial模式,以便于实现多用户的协同开发。然后我们在Global.asax中将注册的路由修改一下:

   1:  private void RegisterRoutes()
   2:  {
   3:      RouteTable.Routes.Add(new ServiceRoute("QDService", new WebServiceHostFactory(), typeof(QDService)));
   4:  }

 这样,当项目运行的时候,就会以QDService为起始点运行。

路由注册完成后,我们就来将Autofac集成到项目中,这里需要集成的dll有两个:

image

其中Autofac是主dll,Autofac.Integration.Wcf是专门针对Wcf注入而设计的扩展。安装Autofac.Integration.Wcf的时候,我们可以使用命令:

Install-Package Autofac.Wcf -version 3.0.0 -project TinyFrame.WebService

由于Autofac.Integration.Wcf 3.0.0需要Autofac 3.0.0及其以上版本的支持,而我们用到的Autofac版本为3.3.0的,所以我们这里使用Autofac.Integration.Wcf的3.0.0版本。

安装完毕后,Webconfig中会自动生成如下的配置:

   1:  <runtime>
   2:      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
   3:        <dependentAssembly>
   4:          <assemblyIdentity name="Autofac" publicKeyToken="17863af14b0044da" culture="neutral" />
   5:          <bindingRedirect oldVersion="0.0.0.0-3.3.0.0" newVersion="3.0.0.0" />
   6:        </dependentAssembly>
   7:        <dependentAssembly>
   8:          <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" />
   9:          <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
  10:        </dependentAssembly>
  11:      </assemblyBinding>
  12:    </runtime>

 如果运行起来的时候,提示如下错误:

未能加载文件或程序集“Autofac, Version=3.3.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)

我们需要将配置中的

   1:  <bindingRedirect oldVersion="0.0.0.0-3.3.0.0" newVersion="3.3.0.0" /> 

修改成

   1:  <bindingRedirect oldVersion="0.0.0.0-3.3.0.0" newVersion="3.0.0.0" />

才可以正常的运行,我不知道为啥,还望知道的朋友们说明一下原因。

上面的步骤进行完毕之后,我们添加添加一个有参数的构造函数,以便于实现Autofac的构造注入:

   1:  public partial class QDService
   2:      {
   3:          public QDService(
   4:                IApplicationService appService
   5:              , ILoggerService logger
   6:              , IUserService userService
   7:              , IRoleService roleService
   8:              , IModelService modelService
   9:              , IOperationService operationService
  10:              , IModelAndOperationService modelOperationService
  11:              , IModelAndRoleService modelRoleService
  12:              , IUserAndRoleService userRoleService
  13:              , ICookie cookieService
  14:              , IMonitorService<t_base_area> baseAreaService
  15:              , IMonitorService<t_base> baseService
  16:              , IMonitorService<t_monitor_equipment_type> equipmentTypeService
  17:              , IMonitorService<t_monitor_equipment> equipmentService
  18:              , IMonitorService<t_monitor_map> baseEquipmentMapService
  19:              , IMonitorService<t_monitor_param> paramService
  20:              , IMonitorDataQueryService dataService
  21:              )
  22:          {
  23:              this.appService = appService;
  24:              this.logger = logger;
  25:              this.userService = userService;
  26:              this.roleService = roleService;
  27:              this.modelService = modelService;
  28:              this.operationService = operationService;
  29:              this.modelOperationService = modelOperationService;
  30:              this.modelRoleService = modelRoleService;
  31:              this.userRoleService = userRoleService;
  32:              this.cookieService = cookieService;
  33:              this.baseAreaService = baseAreaService;
  34:              this.baseService = baseService;
  35:              this.equipmentService = equipmentService;
  36:              this.equipmentTypeService = equipmentTypeService;
  37:              this.baseEquipmentMapService = baseEquipmentMapService;
  38:              this.paramService = paramService;
  39:              this.dataService = dataService;
  40:          }
  41:   
  42:          private readonly IApplicationService appService;
  43:          private readonly ILoggerService logger;
  44:          private readonly IUserService userService;
  45:          private readonly IRoleService roleService;
  46:          private readonly IModelService modelService;
  47:          private readonly IOperationService operationService;
  48:          private readonly IModelAndOperationService modelOperationService;
  49:          private readonly IModelAndRoleService modelRoleService;
  50:          private readonly IUserAndRoleService userRoleService;
  51:          private readonly ICookie cookieService;
  52:          private readonly IMonitorService<t_base_area> baseAreaService;
  53:          private readonly IMonitorService<t_base> baseService;
  54:          private readonly IMonitorService<t_monitor_equipment_type> equipmentTypeService;
  55:          private readonly IMonitorService<t_monitor_equipment> equipmentService;
  56:          private readonly IMonitorService<t_monitor_map> baseEquipmentMapService;
  57:          private readonly IMonitorService<t_monitor_param> paramService;
  58:          private readonly IMonitorDataQueryService dataService;
  59:      }

运行起来以后,提示我们错误如下:

autofac the service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.
 

这里我需要说明一下,在WCF中,由于InstanceContextMode设置为InstanceContextMode.Single的时候,需要无参构造函数,所以在本项目中,我们的构造是带参数的,我们只能设置为PerCall或者是PerSession模式。这里我们就设置为PerSession模式。

设置完成后,我们根据dudu的这篇文章中提到的步骤,一步一步的进行即可:

首先实现IInstanceProvider接口:

   1:  using System;
   2:  using TinyFrame.Services;
   3:  using TinyFrame.Data.DataRepository;
   4:  using Autofac;
   5:  using TinyFrame.Unitofwork;
   6:  using TinyFrame.Framework.Caching;
   7:  using TinyFrame.Framework.Logger;
   8:  using TinyFrame.Framework.Query;
   9:  using TinyFrame.Framework.Cookie;
  10:  using TinyFrame.Data.DataContextFactory;
  11:  using Autofac.Integration.Wcf;
  12:  using System.ServiceModel;
  13:  using System.ServiceModel.Dispatcher;
  14:  using System.ServiceModel.Channels;
  15:   
  16:  namespace TinyFrame.WebService
  17:  {
  18:      public class IocInstanceProvider:IInstanceProvider
  19:      {
  20:          Type serviceType;
  21:          IContainer container;
  22:   
  23:          public IocInstanceProvider(Type serviceType)
  24:          {
  25:              this.serviceType = serviceType;
  26:              container = RegisterDependency();
  27:          }
  28:   
  29:          private IContainer RegisterDependency()
  30:          {
  31:              var builder = new ContainerBuilder();
  32:   
  33:              builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
  34:              builder.RegisterGeneric(typeof(MonitorService<>)).As(typeof(IMonitorService<>));
  35:   
  36:              builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().WithParameter("dbContextFactory", new DbContextFactory());
  37:                 
  38:              builder.RegisterType<UserService>().AsImplementedInterfaces().InstancePerLifetimeScope();
  39:              builder.RegisterType<ServiceNews>().AsImplementedInterfaces().InstancePerLifetimeScope();
  40:              builder.RegisterType<ServiceNewsType>().AsImplementedInterfaces().InstancePerLifetimeScope();
  41:              builder.RegisterType<ServiceProducts>().AsImplementedInterfaces().InstancePerLifetimeScope();
  42:              builder.RegisterType<ServiceProductType>().AsImplementedInterfaces().InstancePerLifetimeScope();
  43:              builder.RegisterType<ServicePublishType>().AsImplementedInterfaces().InstancePerLifetimeScope();
  44:              builder.RegisterType<BBSForum>().AsImplementedInterfaces().InstancePerLifetimeScope();
  45:              builder.RegisterType<BBSReply>().AsImplementedInterfaces().InstancePerLifetimeScope();
  46:              builder.RegisterType<BBSTopic>().AsImplementedInterfaces().InstancePerLifetimeScope();
  47:              builder.RegisterType<BBSUser>().AsImplementedInterfaces().InstancePerLifetimeScope();
  48:              builder.RegisterType<RoleService>().AsImplementedInterfaces().InstancePerLifetimeScope();
  49:              builder.RegisterType<ModelService>().AsImplementedInterfaces().InstancePerLifetimeScope();
  50:              builder.RegisterType<OperationService>().AsImplementedInterfaces().InstancePerLifetimeScope();
  51:              builder.RegisterType<ModelAndOperationService>().AsImplementedInterfaces().InstancePerLifetimeScope();
  52:              builder.RegisterType<DynamicQuery>().AsImplementedInterfaces().InstancePerLifetimeScope();
  53:              builder.RegisterType<ModelAndRoleService>().AsImplementedInterfaces().InstancePerLifetimeScope();
  54:              builder.RegisterType<UserAndRoleService>().AsImplementedInterfaces().InstancePerLifetimeScope();
  55:              builder.RegisterType<MonitorDataQueryService>().AsImplementedInterfaces().InstancePerLifetimeScope();
  56:              builder.RegisterType<CookieWrapper>().AsImplementedInterfaces().InstancePerLifetimeScope();
  57:              builder.RegisterType<LoggerService>().AsImplementedInterfaces().InstancePerLifetimeScope();
  58:   
  59:              builder.RegisterType<ApplicationService>().AsImplementedInterfaces().InstancePerLifetimeScope();
  60:              builder.RegisterType<QDService>().InstancePerLifetimeScope();
  61:   
  62:              builder.RegisterType<MemoryCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").SingleInstance();
  63:   
  64:              return builder.Build();
  65:          }
  66:   
  67:          public object GetInstance(InstanceContext instanceContext, Message message)
  68:          {
  69:              return container.Resolve(serviceType);
  70:          }
  71:   
  72:          public object GetInstance(InstanceContext instanceContext)
  73:          {
  74:              return GetInstance(instanceContext,null);
  75:          }
  76:   
  77:          public void ReleaseInstance(InstanceContext instanceContext, object instance)
  78:          {
  79:              if (instance is IDisposable)
  80:                  ((IDisposable)instance).Dispose();
  81:          }
  82:      }
  83:  }

然后实现IServiceBehavior接口:

   1:  using System;
   2:  using System.ServiceModel.Description;
   3:  using System.ServiceModel;
   4:  using System.Collections.ObjectModel;
   5:  using System.ServiceModel.Channels;
   6:  using System.ServiceModel.Dispatcher;
   7:   
   8:  namespace TinyFrame.WebService
   9:  {
  10:      public class IocServiceBehavior : Attribute, IServiceBehavior
  11:      {
  12:          public void AddBindingParameters( ServiceDescription serviceDescription
  13:                                          , ServiceHostBase serviceHostBase
  14:                                          , Collection<ServiceEndpoint> endpoints
  15:                                          , BindingParameterCollection bindingParameters)
  16:          {
  17:              
  18:          }
  19:   
  20:          public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
  21:          {
  22:              foreach (ChannelDispatcher item in serviceHostBase.ChannelDispatchers)
  23:              {
  24:                  foreach (var ed in item.Endpoints)
  25:                  {
  26:                      if(!ed.IsSystemEndpoint)
  27:                      {
  28:                          ed.DispatchRuntime.InstanceProvider = new IocInstanceProvider(serviceDescription.ServiceType);
  29:                      }
  30:                  }
  31:              }
  32:          }
  33:   
  34:          public void Validate(ServiceDescription serviceDescription,ServiceHostBase serviceHostBase)
  35:          {
  36:          }
  37:      }
  38:  }

最后在QDService.cs类头上,加上[IocServiceBehavior]标签即可实现:

   1:      [ServiceContract]
   2:      [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
   3:      [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
   4:      [IocServiceBehavior]
   5:      public partial class QDService

需要注意的是,RegisterDependency方法中需要将QDService自身的实例进行注入:

   1:   builder.RegisterType<QDService>().InstancePerLifetimeScope();

否则的话,会抛出如下的错误来:

The requested service 'TinyFrame.WebService.QDService' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.

做完这一切之后,我们的所有前期准备工作都已经部署停当,下面是Consume Time!!!!!!

新建一个QDData.cs类并修改类头为:public partial class QDService,加入如下方法:

   1:        [WebInvoke(Method = "GET"
   2:        , ResponseFormat = WebMessageFormat.Xml
   3:        , BodyStyle = WebMessageBodyStyle.Bare
   4:        , UriTemplate = "/GetAllBases/")]
   5:          public List<t_base> GetAllBases()
   6:          {
   7:              var result = baseService.Get(x => x.ID != string.Empty);
   8:   
   9:              //重要
  10:              //这里都需要重新遍历赋值一下,虽然我不知道为什么,但是确实起作用了
  11:   
  12:              var list = new List<t_base>();
  13:              result.ToList().ForEach((item) =>
  14:              {
  15:                  list.Add(new t_base()
  16:                  {
  17:                      Area_ID = item.Area_ID,
  18:                      Base_Area = item.Base_Area,
  19:                      Base_Jin = item.Base_Jin,
  20:                      Base_Name = item.Base_Name,
  21:                      Base_Note = item.Base_Note,
  22:                      Base_Order = item.Base_Order,
  23:                      Base_Wei = item.Base_Wei,
  24:                      ID = item.ID,
  25:                      UpdateTime = item.UpdateTime
  26:                  });
  27:              });
  28:            
  29:              return list;
  30:          }

需要说明的是,虽然我们可以直接利用baseService.Get方法获取出IList<t_base>对象出来,但是我们不能够直接通过result.ToList()进行返回,否则的话将会得不到任何输出,只能将得到的数据遍历一遍,然后加入到新建的List对象中返回,才可奏效。这里非常奇怪,我不知道为什么。还望知道的朋友给解惑一下。

最后看看效果:

image

免责声明:文章转载自《TinyFrame升级之十:WCF Rest Service注入IOC的心》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇springboot中邮箱验证按钮实现60秒后可重新获取(可防刷新)以及防重复发送kubernetes部署的Pod长时处于ContainerCreating状态下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ioctl() 参数

在驱动程序里, ioctl() 函数上传送的变量 cmd 是应用程序用于区别设备驱动程序请求处理内容的值。cmd除了可区别数字外,还包含有助于处理的几种相应信息。 cmd的大小为 32位,共分 4 个域:     bit31~bit30 2位为 “区别读写” 区,作用是区分是读取命令还是写入命令。      bit29~bit15 14位为 "数据大小"...

Spring源码阅读-IoC容器解析

目录 Spring IoC容器 ApplicationContext设计解析 BeanFactory ListableBeanFactory HierarchicalBeanFactory MessageSource ApplicationEventPublisher EnvironmentCapable ResourceLoader和Resour...

如何在IIS中配置WCF

1、先做好WCF项目。2、在IIS中创建应用程序,指定目录里放WCF生成的项目文件。生成部署包。3、在MIME类型中,添加新项,扩展名为:.svc ,类型为application/octet-stream4、在处理程序映射处理添加三项。托管程序处理路径:*.svc ;类型:System.ServiceModel.Activation.ServiceHttp...

我的WCF之旅 (11): 再谈WCF的双向通讯基于Http的双向通讯 V.S. 基于TCP的双向通讯

在一个基于面向服务的分布式环境中,借助一个标准的、平台无关的Communication Infrastructure,各个Service通过SOAP Message实现相互之间的交互。这个交互的过程实际上就是Message Exchange的过程。WCF支持不同形式的Message Exchange,我们把这称之为Message Exchange Patt...

Android基于ksoap2调用WCF服务(二):Android篇

上一篇通过一个非常简单的例子,完成了一个WCF的服务。接下来介绍一下Android端。 Android端调用WCF,采用基于ksoap2包来实现。 下载地址(这个需要fan qiang访问,你们懂的):https://code.google.com/p/ksoap2-android/ 我用的3.3.0版本,我传到csdn上,上面地址如果不能访问,可以用这个...

wcf通道Channel

正文       客户端与服务进行交互的过程是通过通道进行交互的。客户端通过调用代理类执行相应的方法,通过通道编码,调用上下文,传输客户端的事务,管理可靠会话,对消息正文的加密,最后要执行的通道是传输通道就像我们七层的最后一层是物理传输层与服务端的那一头的传输通道交接。服务端拿到以后会逐个拆包,然后交给分发器,分发器交给对应的服务处理。         ...