【WCF】自动加载 WCF Library

在论坛里遇到一个问题:如何做一个主程序,主程序里没有任何契约和配置文件能自动Host指定的外部的WCF Library Assembly。其实Visual Studio已经提供了类似的玩意,在你创建一个WCF Library工程之后在项目属性 -> WCF Options -> 会看到一个 "Start WCF Service Host When debugging anther project in same solution" 的选项,如果选上那么VS会自动调用 WcfSvcHost.exe 这个工具帮你托管 WCF 服务。而且VS一并提供的 WCF Test Client  给开发者十分方便的测试体验:



话说回来,通过对 Config 文件中的 serviceModel 配置节做解析完全可以自己实现,下面提供简单的实现方法:【示例代码下载】

(当然下面的方法还比较简陋,没有考虑什么安全配置、还有一些定义的Behavior等)
加载服务:

public static Dictionary<string, Tuple<Type, Binding, Uri>> LoadHost(Assembly assembly)
 {
     var config = ConfigurationManager.OpenExeConfiguration(assembly.Location);
     var svcConfig = (ServiceModelSectionGroup)config.GetSectionGroup("system.serviceModel");
     var contracts = new Dictionary<string, Tuple<Type, Binding, Uri>>();

     foreach (ServiceElement se in svcConfig.Services.Services)
     {
         var serviceType = assembly.GetType(se.Name);
         var host = new ServiceHost(serviceType);
         Uri baseAddress = null;

         foreach (BaseAddressElement ba in se.Host.BaseAddresses)
         {
             if (baseAddress == null)
             {
                 baseAddress = new Uri(ba.BaseAddress);
                 break;
             }
         }
         foreach (ServiceEndpointElement e in se.Endpoints)
         {
             if (!e.Binding.StartsWith("mex"))
             {
                 var contract = assembly.GetType(e.Contract);
                 var address = new Uri(baseAddress, e.Address);
                 var binding = MapBinding(address.Scheme);
                 host.AddServiceEndpoint(contract, binding, address);
                 contracts.Add(e.Contract, new Tuple<Type, Binding, Uri>(contract, binding, address));
                 host.Open();
                 Console.WriteLine(se.Name + " started...");
             }
         }
     }
     return contracts;
 }

通过传入的 Assembly 可以找到对应的 xxx.dll.config 文件,然后解析其中的 “system.serviceModel" 配置节。为了之后的测试,返回一个 Dictionary,
因为客户端可以通过 ChannelFactory<T>.CreateChannel(Binding, EndpointAddress) 创建连接,所以顺便把需要的数据带回来。

加载客户端:
public static dynamic LoadClient(Type contract, Binding binding, Uri address)
{
    var createChannel = typeof(ChannelFactory<>).MakeGenericType(contract).GetMethod("CreateChannel", 
                            new Type[] { typeof(Binding), typeof(EndpointAddress) });
    dynamic channel = createChannel.Invoke(null, new object[] { binding, new EndpointAddress(address) });
    return channel;
}
一切为了方便使用了 dynamic 类型,因为你在测试的时候一定是知道服务端的接口定义的。

运行示例:

static void Main(string[] args)
{
    var wcfLibrary = "WcfServiceLibrary1.dll";
    var assembly = Assembly.LoadFrom(wcfLibrary);
    var contracts = LoadHost(assembly);

    var testContract = contracts["WcfServiceLibrary1.IService1"];
    dynamic client = LoadClient(testContract.Item1, testContract.Item2, testContract.Item3);
    var test1 = client.GetData(123);
    Console.WriteLine(test1);

    dynamic complexObj = assembly.CreateInstance("WcfServiceLibrary1.CompositeType");
    complexObj.BoolValue = true;
    complexObj.StringValue = "hello";
    dynamic test2 = client.GetDataUsingDataContract(complexObj);
    Console.WriteLine(test2.StringValue);

    Console.Read();
}


其实我能想到上面的代码能用到地方就是自动化测试了... 另外考虑到安全的隔离每个WCF Library,应该考虑封装在 AppDomain 中。
感兴趣的童鞋,可以自己修改一下代码:使用 AppDomain.DoCallback() 封装上面的 LoadHost,需要注意的是 AppDomain 的独立性,
代理中不能有任何当前domain的数据上下文否则会抛异常。(可以使用 AppDomain.SetData / GetData 传送一些参数)


  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 19
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值