Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用自托管时,我是否可以在app.config中自动托管所有服务?_C#_Wcf_Self Hosting_Wcf Hosting - Fatal编程技术网

C# 使用自托管时,我是否可以在app.config中自动托管所有服务?

C# 使用自托管时,我是否可以在app.config中自动托管所有服务?,c#,wcf,self-hosting,wcf-hosting,C#,Wcf,Self Hosting,Wcf Hosting,我正在编写一个需要承载多个WCF服务的应用程序。WCF的优势之一是,通过在app.config文件中指定设置,可以配置服务,而无需重新编译 自托管时,似乎没有现成的方式自动托管app.config文件中的服务。我找到了,其中提到了一种可能的解决方案,即在运行时动态枚举app.config中列出的服务,并为每个服务创建一个ServiceHost 但是,我的服务、合同和托管应用程序都位于不同的程序集中。这会导致Type.GetType(字符串名称)无法找到我的服务类型(返回null),因为它是在不同

我正在编写一个需要承载多个WCF服务的应用程序。WCF的优势之一是,通过在app.config文件中指定设置,可以配置服务,而无需重新编译

自托管时,似乎没有现成的方式自动托管app.config文件中的服务。我找到了,其中提到了一种可能的解决方案,即在运行时动态枚举app.config中列出的服务,并为每个服务创建一个ServiceHost

但是,我的服务、合同和托管应用程序都位于不同的程序集中。这会导致
Type.GetType(字符串名称)
无法找到我的服务类型(返回
null
),因为它是在不同的程序集中定义的

如何在我的自托管应用程序中可靠地动态托管app.config文件中列出的所有服务(即,无需硬编码
新服务主机(typeof(MyService))

注意:My app.config是使用Visual Studio 2010中的“WCF配置编辑器”生成的

另外请注意:我的主要目标是由app.config文件驱动,因此只有一个配置点。我不想在单独的位置进行配置

编辑:我能够读取app.config文件(请参见),但需要能够解析不同程序集中的类型

编辑:下面的一个答案提示我尝试在app.config中指定AssemblyQualifiedName,而不仅仅是基本类型名称。这能够解决
type.GetType()
问题,但是
ServiceHost.Open()
现在失败,出现
无效操作异常
,无论我如何获得类型:

// Fails
string typeName = typeof(MyService).AssemblyQualifiedName;
Type myType = Type.GetType(typeName);
ServiceHost host = new ServiceHost(myType);
host.Open(); // throws InvalidOperationException

// Also fails
Type myType2 = typeof(MyService);
ServiceHost host2 = new ServiceHost(myType2);
host2.Open(); // throws InvalidOperationException
例外情况详情:

Service'SO.Example.MyService'没有应用程序(非基础结构)终结点。这可能是因为找不到应用程序的配置文件,或者因为在配置文件中找不到与服务名称匹配的服务元素,或者因为在服务元素中未定义终结点。

我猜WCF在内部解析app.config文件时会尝试匹配服务名称的文本字符串

EDIT/ANSWER:我最后做的基本上就是下面的答案。我没有使用
Type.GetType()
,而是知道我所有的服务都在同一个程序集中,所以我切换到:

// Get a reference to the assembly which contain all of the service implementations.
Assembly implementationAssembly = Assembly.GetAssembly(typeof(MyService));
...
// When loading the type for the service, load it from the implementing assembly.
Type implementation = implementationAssembly.GetType(serviceElement.Name);

这肯定是可能的!看看这个代码片段——用它作为基础,从这里开始:

using System.Configuration;   // don't forget to add a reference to this assembly!

// get the <system.serviceModel> / <services> config section
ServicesSection services = ConfigurationManager.GetSection("system.serviceModel/services") as ServicesSection;

// enumerate over each <service> node
foreach(ServiceElement aService in services.Services)
{
    Console.WriteLine();
    Console.WriteLine("Name: {0} / Behavior: {1}", aService.Name, aService.BehaviorConfiguration);

    // enumerate over all endpoints for that service
    foreach (ServiceEndpointElement see in aService.Endpoints)
    {
        Console.WriteLine("\tEndpoint: Address = {0} / Binding = {1} / Contract = {2}", see.Address, see.Binding, see.Contract);
    }
}

您在问题链接中正确地找到了问题的答案,@marc_的答案也给出了正确的方法。您面临的实际问题是,您需要动态获取程序集的类型实例,该程序集只能通过配置文件引用,因此它可能不会加载到当前AppDomain中

请在代码中查看这一点。尽管本文是专门针对ASP.NET应用程序的,但一般的方法应该适用于自托管场景。其思想是将Type.GetType(string)调用替换为动态加载所请求程序集的私有方法调用(如果需要)并返回类型对象。您发送此方法的参数仍然是元素。名称,并且您需要确定要加载的正确程序集。一个简单的基于约定的程序集命名方案应该可以工作。例如,如果服务类型为:

MyNamespace.MyService.MyServiceImpl

然后假设组件为:

MyNamespace.MyService

//获取/config节
ServicesSection services=ConfigurationManager.GetSection(“system.serviceModel/services”)作为ServicesSection;
//全班上课
var allTypes=AppDomain.CurrentDomain.GetAssemblies().ToList().SelectMany(s=>s.GetTypes())。其中(t=>t.IsClass==true);
//枚举每个节点
foreach(services.services中的servicelement服务)
{
类型serviceType=allTypes.SingleOrDefault(t=>t.FullName==service.Name);
if(serviceType==null)
{
继续;
}
ServiceHost ServiceHost=新的ServiceHost(serviceType);
Open();
}

基于其他答案,我将代码扩展到以下内容,在app.config中搜索所有程序集中的服务

我看不出这与我链接的问题有什么不同。我是否遗漏了什么?我目前的主要问题是
Type.GetType(字符串名)
返回null。我已经能够从app.config文件中找到类型名称。我知道实际的问题,这就是为什么我将其包含在问题描述中。您引用的博客文章很有趣,内容丰富,但似乎相当繁重。基于命名空间动态加载程序集的建议似乎合理。仔细考虑一下,我想知道是否可以输入程序集限定类型名(type.AssemblyQualifiedName,包括程序集引用)在app.config文件中,而不是默认的软类型名称中。希望这能起作用。如果不行,可以通过使用configuration runtime元素为应用程序设置配置来从配置文件加载程序集。这将负责将程序集加载到AppDomain中。您只需要使用反射来获取类型实例您正在启动的服务。无法运行。
Type.GetType()
能够加载该类型,但是
ServiceHost.Open()
在使用它创建时失败。当.Open()时引发了什么异常失败?更新了带有更多详细信息的问题。看起来我的代码现在能够找到类型,但现在WCF无法在app.config中找到匹配的服务(可能它正在查找类型名称的分类器表单)。Arg。是的,服务
// find currently executing assembly
Assembly curr = Assembly.GetExecutingAssembly();

// get the directory where this app is running in
string currentLocation = Path.GetDirectoryName(curr.Location);

// find all assemblies inside that directory
string[] assemblies = Directory.GetFiles(currentLocation, "*.dll");

// enumerate over those assemblies
foreach (string assemblyName in assemblies)
{
   // load assembly just for inspection
   Assembly assemblyToInspect = Assembly.ReflectionOnlyLoadFrom(assemblyName);

   if (assemblyToInspect != null)
   {
      // find all types
      Type[] types = assemblyToInspect.GetTypes();

      // enumerate types and determine if this assembly contains any types of interest
      // you could e.g. put a "marker" interface on those (service implementation)
      // types of interest, or you could use a specific naming convention (all types
      // like "SomeThingOrAnotherService" - ending in "Service" - are your services)
      // or some kind of a lookup table (e.g. the list of types you need to find from
      // parsing the app.config file)
      foreach(Type ty in types)
      {
         // do something here
      }
   }
}
    // get the <system.serviceModel> / <services> config section
    ServicesSection services = ConfigurationManager.GetSection("system.serviceModel/services") as ServicesSection;

    // get all classs
    var allTypes = AppDomain.CurrentDomain.GetAssemblies().ToList().SelectMany(s => s.GetTypes()).Where(t => t.IsClass == true);

    // enumerate over each <service> node
    foreach (ServiceElement service in services.Services)
    {
        Type serviceType = allTypes.SingleOrDefault(t => t.FullName == service.Name);
        if (serviceType == null)
        {
            continue;
        }

        ServiceHost serviceHost = new ServiceHost(serviceType);
        serviceHost.Open();
    }