Pergunta

Alguém conseguiu se comunicar usando o WCF no Windows Phone Series 7 Emulator?

Eu tenho tentado nos últimos dois dias e isso está acontecendo para mim. Eu posso fazer com que um controle normal do Silverlight funcione em Silverlight 3 e Silverlight 4, mas não na versão do telefone. Aqui estão duas versões que eu tentei:

Versão 1 - Usando o padrão assíncrono

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

Esta versão quebra nesta linha:

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

Jogando System.NotSupportedException. A exceção não é muito descritiva e a pilha de call não é igualmente muito útil:

em system.Servicemodel.Diagnóstica.Exceptionutility.BuildMessage (Exceção x) em System.Servicemodel.diagnóstica.Exceptionutily.LogException (Exceção x) AT System.Servicemodel.diagNosticutility.Exception.TeMoMActility.ChemoxTerRorRorRorRorror (Excepctemodel.diagnosticutility.Exception.HrowhELperRorrorRorrorRorRorrorRorRorRorror (excepcionário). .CreateChannel (EndPointAddress) em windowsphoneApplication2.mainpage.dologin () ....

Versão 2 - Bloqueando a chamada WCF

Aqui está a versão que não usa o padrão assíncrono.

[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");

Esta versão trava System.ServiceModel.ClientBase<TChannel> construtor. A pilha de chamadas é um pouco diferente:

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) em System.Servicemodel.Description.Typeloader.LoadContRentDescriptionHelper (Type ContractType, Type ServiceType, Object ServiceImple mentação) em System.Servicemodel.Description.Typeloader.LoadContRentDescription (Type ContractType) em System.Servicemodel.ChannEflactory1.CreateDescription()
   at System.ServiceModel.ChannelFactory.InitializeEndpoint(Binding binding, EndpointAddress address)
   at System.ServiceModel.ChannelFactory1..ctor (ligação de ligação, endpointAddress remoteaddress) em system.servicemodel.clientbase1..ctor(Binding binding, EndpointAddress remoteAddress)
   at Wcf.WcfClientBase1..ctor (nome da string, streaming booleano) em wcf.wcfclientbase`1..ctor (nome da string) em wcf.authenticationclient..ctor () em windowsphoneApplication2.mainpage.dologin () ...

Alguma ideia?

Foi útil?

Solução

Como Scottmarlowe apontou, o serviço de serviço gerado automaticamente funciona apenas. Eu decidi descobrir por que o inferno sangrento funciona e a versão manual não.

Eu encontrei o culpado e é ChannelFactory. Por algum motivo new ChannelFactory<T>().CreateChannel() Apenas joga uma exceção. A única solução que encontrei é fornecer sua própria implementação do canal. Isso involve:

  1. Substitua o cliente da base. (opcional).
  2. Substitua o clientbase.createChannel. (opcional).
  3. Subclasse ChannelBase com uma implementação específica da sua interface WCF

Agora, o ClientBase já fornece uma instância da fábrica de canais através ChannelFactory propriedade. Se você simplesmente ligar CreateChannel Fora que você obteria a mesma exceção. Você precisa instanciar um canal que você define na etapa 3 de dentro CreateChannel.

Este é o quadro de arame básico de como tudo parece montado.

[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; Se você deseja usar seu próprio código WCF no WP7, você precisa criar sua própria classe de canal e não confiar ChannelFactory.

Outras dicas

A criação dinâmica de proxy usando o ChannelFActory.createChannel () não é suportada no Windows Phone. Isso está documentado aqui - http://msdn.microsoft.com/en-us/library/ff426930(vs.96).aspx

Consumir um serviço usando o mecanismo 'Adicionar referência de serviço' em um padrão assíncrono seria a maneira correta de fazer.

Não tive nenhum problema, mas segui a rota "Adicionar referência ..." que eu tive que fazer via "vs2010 Express for Windows Phone" b/c vs2010 RC ainda não suporta esse recurso para o desenvolvimento do WP7. A versão expressa vem com a instalação do desenvolvedor do WP7.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top