代码之家  ›  专栏  ›  技术社区  ›  Igor Zevaka

在Windows Phone 7上使用WCF的System.UnsupportedException

  •  4
  • Igor Zevaka  · 技术社区  · 15 年前

    是否有人能够在WindowsPhoneSeries 7模拟器上使用WCF进行通信?

    过去两天我一直在努力,但这一切都发生在我身上。我可以让一个普通的silverlight控件同时在silverlight 3和silverlight 4中工作,但不能在手机版本中工作。我试过两个版本:

    版本1-使用异步模式

    BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
    EndpointAddress endpointAddress = new EndpointAddress("http://localhost/wcf/Authentication.svc");
    Wcf.IAuthentication auth1 = new ChannelFactory<Wcf.IAuthentication>(basicHttpBinding, endpointAddress).CreateChannel(endpointAddress);
    
    AsyncCallback callback = (result) =>
    {
    
        Action<string> write = (str) =>
        {
            this.Dispatcher.BeginInvoke(delegate
            {
                //Display something
            });
        };
    
        try
        {
            Wcf.IAuthentication auth = result.AsyncState as Wcf.IAuthentication;
            Wcf.AuthenticationResponse response = auth.EndLogin(result);
            write(response.Success.ToString());
        }
        catch (Exception ex)
        {
            write(ex.Message);
            System.Diagnostics.Debug.WriteLine(ex.Message);
        }
    };
    
    auth1.BeginLogin("user0", "test0", callback, auth1);
    

    此版本在此行中断:

    Wcf.IAuthentication auth1 = new ChannelFactory<Wcf.IAuthentication>(basicHttpBinding, endpointAddress).CreateChannel(endpointAddress);
    

    投掷 System.NotSupportedException . 异常不是很有描述性,调用堆栈也不是很有帮助:

    
       at System.ServiceModel.DiagnosticUtility.ExceptionUtility.BuildMessage(Exception x)
       at System.ServiceModel.DiagnosticUtility.ExceptionUtility.LogException(Exception x)
       at System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exception e)
       at System.ServiceModel.ChannelFactory`1.CreateChannel(EndpointAddress address)
       at WindowsPhoneApplication2.MainPage.DoLogin()
       ....
    

    版本2-阻止WCF调用

    下面是不使用异步模式的版本。

    [System.ServiceModel.ServiceContract]
    public interface IAuthentication
    {
        [System.ServiceModel.OperationContract]
        AuthenticationResponse Login(string user, string password);
    }
    
    public class WcfClientBase<TChannel> : System.ServiceModel.ClientBase<TChannel> where TChannel : class {
            public WcfClientBase(string name, bool streaming)
                : base(GetBinding(streaming), GetEndpoint(name)) {
                ClientCredentials.UserName.UserName = WcfConfig.UserName;
                ClientCredentials.UserName.Password = WcfConfig.Password;
            }
            public WcfClientBase(string name) : this(name, false) {}
    
            private static System.ServiceModel.Channels.Binding GetBinding(bool streaming) {
                System.ServiceModel.BasicHttpBinding binding = new System.ServiceModel.BasicHttpBinding();
                binding.MaxReceivedMessageSize = 1073741824;
                if(streaming) {
                    //binding.TransferMode = System.ServiceModel.TransferMode.Streamed;
                }
                /*if(XXXURLXXX.StartsWith("https")) {
                    binding.Security.Mode = BasicHttpSecurityMode.Transport;
                    binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
                }*/
                return binding;
            }
    
            private static System.ServiceModel.EndpointAddress GetEndpoint(string name) {
                return new System.ServiceModel.EndpointAddress(WcfConfig.Endpoint + name + ".svc");
            }
    
            protected override TChannel CreateChannel()
            {
                throw new System.NotImplementedException();
            }
        }
    
    
    auth.Login("test0", "password0");
    

    此版本崩溃 System.ServiceModel.ClientBase<TChannel> 构造器。调用堆栈有点不同:

    
       at System.Reflection.MethodInfo.get_ReturnParameter()
       at System.ServiceModel.Description.ServiceReflector.HasNoDisposableParameters(MethodInfo methodInfo)
       at System.ServiceModel.Description.TypeLoader.CreateOperationDescription(ContractDescription contractDescription, MethodInfo methodInfo, MessageDirection direction, ContractReflectionInfo reflectionInfo, ContractDescription declaringContract)
       at System.ServiceModel.Description.TypeLoader.CreateOperationDescriptions(ContractDescription contractDescription, ContractReflectionInfo reflectionInfo, Type contractToGetMethodsFrom, ContractDescription declaringContract, MessageDirection direction)
       at System.ServiceModel.Description.TypeLoader.CreateContractDescription(ServiceContractAttribute contractAttr, Type contractType, Type serviceType, ContractReflectionInfo& reflectionInfo, Object serviceImplementation)
       at System.ServiceModel.Description.TypeLoader.LoadContractDescriptionHelper(Type contractType, Type serviceType, Object serviceImplementation)
       at System.ServiceModel.Description.TypeLoader.LoadContractDescription(Type contractType)
       at System.ServiceModel.ChannelFactory1.CreateDescription()
       at System.ServiceModel.ChannelFactory.InitializeEndpoint(Binding binding, EndpointAddress address)
       at System.ServiceModel.ChannelFactory1..ctor(Binding binding, EndpointAddress remoteAddress)
       at System.ServiceModel.ClientBase1..ctor(Binding binding, EndpointAddress remoteAddress)
       at Wcf.WcfClientBase1..ctor(String name, Boolean streaming)
       at Wcf.WcfClientBase`1..ctor(String name)
       at Wcf.AuthenticationClient..ctor()
       at WindowsPhoneApplication2.MainPage.DoLogin()
       ...
    

    有什么想法吗?

    4 回复  |  直到 13 年前
        1
  •  7
  •   Indy9000    13 年前

    正如Scottmarlowe所指出的那样,自动生成的服务引用只是起作用。我的任务是弄清楚为什么这个该死的东西能用,而手动版本却不行。

    我找到了罪犯 ChannelFactory . 不知为什么 new ChannelFactory<T>().CreateChannel() 只是抛出一个例外。我找到的唯一解决方案是提供您自己的通道实现。这包括:

    1. 覆盖客户端。(可选)。
    2. 重写clientbase.createchannel。(可选)。
    3. 使用wcf接口的特定实现子类channelbase

    现在,clientbase已经通过 渠道工厂 财产。如果你只是打电话 CreateChannel 你会得到同样的例外。您需要从内部实例化在步骤3中定义的通道 创建频道 .

    这是一个基本的线框,它是如何把所有的看起来放在一起的。

    [DataContractAttribute]
    public partial class AuthenticationResponse {
    [DataMemberAttribute]
    public bool Success {
        get; set;
    }
    
    [System.ServiceModel.ServiceContract]
    public interface IAuthentication
    {
        [System.ServiceModel.OperationContract(AsyncPattern = true)]
        IAsyncResult BeginLogin(string user, string password, AsyncCallback callback, object state);
        AuthenticationResponse EndLogin(IAsyncResult result);
    }
    
    public class AuthenticationClient : ClientBase<IAuthentication>, IAuthentication {
    
        public AuthenticationClient(System.ServiceModel.Channels.Binding b, EndpointAddress ea):base(b,ea)
        {
        }
    
        public IAsyncResult BeginLogin(string user, string password, AsyncCallback callback, object asyncState)
        {
            return base.Channel.BeginLogin(user, password, callback, asyncState);
        }
    
        public AuthenticationResponse EndLogin(IAsyncResult result)
        {
            return Channel.EndLogin(result: result);
        }
    
        protected override IAuthentication CreateChannel()
        {
            return new AuthenticationChannel(this);
        }
    
        private class AuthenticationChannel : ChannelBase<IAuthentication>, IAuthentication
        {
            public AuthenticationChannel(System.ServiceModel.ClientBase<IAuthentication> client)
            : base(client)
            {
            }
    
            public System.IAsyncResult BeginLogin(string user, string password, System.AsyncCallback callback, object asyncState)
            {
                object[] _args = new object[2];
                _args[0] = user;
                _args[1] = password;
                System.IAsyncResult _result = base.BeginInvoke("Login", _args, callback, asyncState);
                return _result;
            }
    
            public AuthenticationResponse EndLogin(System.IAsyncResult result)
            {
                object[] _args = new object[0];
                AuthenticationResponse _result = ((AuthenticationResponse)(base.EndInvoke("Login", _args, result)));
                return _result;
            }
        }
    }
    

    TLDR; 如果要在wp7上使用自己的wcf代码,则需要创建自己的通道类,而不依赖于 渠道工厂 .

        2
  •  1
  •   Vijay Verma    15 年前

    Windows Phone不支持使用channelFactory.createChannel()创建动态代理。这里有记录- http://msdn.microsoft.com/en-us/library/ff426930(VS.96).aspx

    使用异步模式中的“添加服务引用”机制使用服务是正确的方法。

        4
  •  0
  •   Scott Marlowe    15 年前

    我没有遇到任何问题,但我走了“添加服务引用…”的路线,我不得不通过“VS2010 Express for Windows Phone”b/c VS2010 RC还不支持WP7开发的功能。express版本随wp7开发人员的安装一起提供。