以编程方式配置端点

时间:2012-09-27 09:56:36

标签: c# windows-8

首先,让我首先说我没有做端点/网络类型的东西的经验,所以我的问题可能看起来有点愚蠢,所以请耐心等待:)

我正在努力将为Windows Phone 7编写的应用程序移植到Windows 8(Metro应用程序)上。在原始应用程序中,有一个ServicesReference.ClientConfig文件,它定义了应用程序连接到服务器的URL,绑定和其他位(地址已更改):

<client>
  <endpoint address="https://someurl.com/userservice.svc"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_UserServices"
        contract="UserApi.UserServices" name="User_Services" />
  <endpoint address="https://someurel.com/dataservice.svc"
      binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_DataServices"
      contract="DataApi.DataServices" name="Data_Services" />

此外,在WP7项目中,已经添加了两个“服务引用”(一个用于用户服务,一个用于数据服务),并支持Reference.cs生成的文件。当我尝试将服务引用添加到Win8项目(VS2012)中时,它生成了一个空白的reference.cs文件,因此我只是将WP7项目中的Reference.cs文件添加到W8项目中,并复制了ServiceReferences.ClientConfig文件进入W8项目(所以在目录结构方面,它看起来与WP7项目相同)。 我认为这些Reference.cs文件是为合同提供接口的文件

现在,当我运行W8应用程序时,在需要访问服务的部分出现错误:

  

用户代码未处理InvalidOperationException   找不到具有名称的端点元素   'User_Services'和合同   ServiceModel客户端中的“UserApi.UserServices”   配置部分。这可能是因为没有配置文件   找到您的应用程序,或者因为没有端点元素匹配   这个名字可以在客户端元素中找到。

所以我认为App没有使用ServicesReferces.ClientConfig文件来获取端点和网络地址,或者它没有找到我已导入项目的Reference.cs文件。因此,首先假设它没有通过ServicesReferences.ClientConfig文件正确找到端点,是否可以在代码中执行相同的操作?

到目前为止我得到的是:

BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint = new EndpointAddress(new Uri("https://someurl.com/someservice.svc"));

但我不知道如何进一步(我将其添加到App.xaml.cs中)

希望这个问题有道理。如果您需要任何进一步的信息,请告诉我,我会在我去了解更多有关此终端业务的情况时尝试了解它

提前致谢

1 个答案:

答案 0 :(得分:1)

我遇到了同样的问题,我试图将所有内容都包装在一些类中。这就是我所做的: 首先,我创建了一个名为ClientService的类,它创建并包装EndpointAdress:

为Win8编辑:

public class ClientService
{
   public Type ContractType {get;set;}
   public EndpointAdress EndpointAdress {get;set;}
   public Binding Binding { get; private set; }

   public ClientService(Type contractType)
   {
     ContractType = contractType;
     CreateEndpoint();
     CreateBinding();
   }

   private void CreateEndpoint()
   {
       EndpointAdress = new EndpointAddress(....) //You can get some parameters about the service adress in the Constructor of this class
   } 

   private void CreateBinding()
   {
       Binding = new BasicHttpBinding();  //Or your specific Binding
   }
}

有了这个,我创建了一个包含所有客户注册的静态类。我启动应用程序后添加所有这些内容。像这样:

ClientServices.AddClientService(new ClientService(typeof(IYourService));


public static class ClientServices
{
    private static readonly Dictionary<Type, ClientService> _clientServices;

    static ClientServices()
    {
        _clientServices = new Dictionary<Type, ClientService>();
    }

    public static void AddClientService(ClientService clientService)
    {
        if (!_clientServices.ContainsKey(clientService.ContractType))
        {
            _clientServices.Add(clientService.ContractType, clientService);
        }
    }

    public static ClientService GetClientServiceBy(Type contract)
    {
        if (_clientServices.ContainsKey(contract))
        {
            return _clientServices[contract];
        }
        throw new ArgumentException(string.Format("The contract's Type {0} is not registered. Please register the client's endpoint.", contract));
    }
}

因此,当我的应用程序启动时,我将所有客户端端点都注册在静态类中。现在,当我想调用服务时,我有一个名为ServiceInvoker的包装器。每当我想打电话给服务时,我都会这样使用它:

var invoker = new ServiceInvoker();
    var result = invoker.InvokeService<IMyService, MyObjectReturnType>(
        proxy => proxy.DoSomething(myParameters));
    return result;

InvokeService如下所示:

public TResult InvokeService<TServiceContract, TResult>(Func<TServiceContract, TResult> invokeHandler) where TServiceContract : class
{
    ICommunicationObject communicationObject;
    var arg = CreateCommunicationObject<TServiceContract>(out communicationObject);
    var result = default(TResult);
    try
    {
        result = invokeHandler(arg);
    }
    catch (Exception ex)
    {
        throw;
    }

    finally
    {
        try
        {
            if (communicationObject.State != CommunicationState.Faulted)
                communicationObject.Close();
        }
        catch
        {
            communicationObject.Abort();
        }
    }
    return result;
}

private TServiceContract CreateCommunicationObject<TServiceContract>(out ICommunicationObject communicationObject)
    where TServiceContract : class
{
        var clientService = GetClientService(typeof(TServiceContract));
         var arg = new ChannelFactory<TServiceContract>(clientService.Binding, clientService.EndpointAdress).CreateChannel();
        communicationObject = (ICommunicationObject)arg;
        return arg;
}

private ClientService GetClientService(Type type)
    {
        var clientService = ClientServices.GetClientServiceBy(type);
        return clientService;
    }

这里的主要问题是,由于无法在Windows应用商店应用中引用DLL,因此使此示例工作的唯一方法是复制我们传输到类库的所有服务接口和可能的对象(Windows应用商店)应用)。这样我们就可以创建一个频道并连接到WCF服务。 复制接口可能是一种解决方法,但不是一个好方法。 服务参考或其他代码生成工具是可行的方法。

此外,在这种情况下无法进行异步和等待。

** ServiceInvoker apprach用于creating WCF ChannelFactory