0

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

我正在为 Windows Phone 7 编写的应用程序移植到 Windows 8(Metro 应用程序)上。在原始 App 中,有一个 ServicesReference.ClientConfig 文件,它定义了 App 连接到服务器的 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 在 ServiceModel 客户端配置部分中找不到名称为“User_Services”和合同“UserApi.UserServices”的端点元素。这可能是因为没有为您的应用程序找到配置文件,或者因为在客户端元素中找不到与此名称匹配的端点元素。

所以我认为应用程序没有使用 ServicesReferces.ClientConfig 文件来获取端点和网络地址,或者它没有找到我已导入项目的 Reference.cs 文件。那么,假设首先它没有通过 ServicesReferences.ClientConfig 文件正确找到端点,是否可以在代码中做同样的事情?

到目前为止,我得到的是:

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

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

希望这个问题有意义。如果您需要任何进一步的信息,请告诉我,我会在去的时候尝试了解它,并在此端点业务上对自己进行更多教育

提前致谢

4

1 回答 1

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;
    }

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

此外,在这种情况下,异步和等待是不可能的。

**ServiceInvoker apprach 用于创建 WCF ChannelFactory

于 2012-09-27T10:20:32.753 回答