Usuário com melhor resposta
Problemas em compatibilidade com BasicHttpBinding

Pergunta
-
Olá pessoal, tudo bem?
Estou com o seguinte problema: Eu tinha um servidor WebService que minhas aplicações mobiles acessavam ele, agora que estou tentando converter meu servidor pra WCF, esta acontecendo o seguinte problema quando as aplicações tenta invocar qualquer método:
Falha na solicitação com status HTTP 415: Cannot process the message because the content type 'application/soap+xml; charset=utf-8; action="http://tempuri.org/IWCFCompuService/GetFormPag"' was not the expected type 'text/xml; charset=utf-8'..
aproveitando o post, quero perguntar também se consigo ultilizar o tipo "WSHttpbinding" mesmo com a framework sendo 2.0, por que eu tentei mas a aplicação tenta conectar por 1 min e nada. O código do meu server está aí em baixo:
Mexbinding = new System.ServiceModel.Channels.TcpTransportBindingElement(); System.ServiceModel.Channels.CustomBinding customBinding = new System.ServiceModel.Channels.CustomBinding(Mexbinding); AsyncCallback callback = new AsyncCallback(SyncOpen); IAsyncResult result = null; hostPrincipal = new ServiceHost(principal.GetType()); tcpBinding = new NetTcpBinding(SecurityMode.Message, true); tcpBinding.TransactionFlow = true; tcpBinding.MaxBufferSize = int.MaxValue; tcpBinding.MaxBufferPoolSize = int.MaxValue; tcpBinding.MaxReceivedMessageSize = int.MaxValue; basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.None); basicHttpBinding.MaxBufferPoolSize = int.MaxValue; basicHttpBinding.MaxBufferSize = int.MaxValue; basicHttpBinding.MaxReceivedMessageSize = int.MaxValue; basicHttpBinding.TextEncoding = Encoding.UTF8; basicHttpBinding.MessageEncoding = WSMessageEncoding.Text; /*HttpBinding = new WSHttpBinding(SecurityMode.Message, true); HttpBinding.TransactionFlow = true; HttpBinding.MaxBufferPoolSize = int.MaxValue; HttpBinding.MaxReceivedMessageSize = int.MaxValue;*/ namedPipeBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport); namedPipeBinding.MaxBufferPoolSize = int.MaxValue; namedPipeBinding.MaxBufferSize = int.MaxValue; namedPipeBinding.MaxReceivedMessageSize = int.MaxValue; namedPipeBinding.TransactionFlow = true; hostPrincipal.AddServiceEndpoint(typeof(CompuService.IWCFCompuService), tcpBinding, uriNetTcp); hostPrincipal.AddServiceEndpoint(typeof(CompuService.IWCFCompuService), basicHttpBinding, uriWSHttp); hostPrincipal.AddServiceEndpoint(typeof(CompuService.IWCFCompuService), namedPipeBinding, uriNetPipe); metaData = hostPrincipal.Description.Behaviors.Find<ServiceMetadataBehavior>(); if (metaData == null) { metaData = new ServiceMetadataBehavior(); metaData.HttpGetUrl = new Uri("http://localhost:90/CompuService"); metaData.HttpGetEnabled = true; //metaData.HttpGetBinding = basicHttpBinding; hostPrincipal.Description.Behaviors.Add(metaData); } hostPrincipal.AddServiceEndpoint(typeof(IMetadataExchange), customBinding, uriNetTcpMex); hostPrincipal.Closing += new EventHandler(Host_Closing); result = hostPrincipal.BeginOpen(callback, principal); hostPrincipal.EndOpen(result);
desde já agradeço
Respostas
-
Boas Pedro,
Para você ter uma ideia do que fiz aqui para reproduzir:
Crei uma aplicação ASP.NET Web Services (ASMX) com um único serviço, que está abaixo:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public DataSet HelloWorld()
{
DataSet ds = new DataSet();
DataTable dt = new DataTable();
dt.Columns.Add("Nome");
dt.Rows.Add("Israel");ds.Tables.Add(dt);
return ds;
}
}
Depois disso, rodei o serviço e ele foi publicado no seguinte endereço: http://localhost:51982/Service1.asmx. Com isso, fiz a referência para o mesmo em uma aplicação Windows para assim consumir. Depois da referência feita (utilizando a opção antiga, que é para referenciar serviços ASMX), eu escrevi o seguinte código para consumo:
Service1 s = new Service1();
DataSet ds = s.HelloWorld();
Console.WriteLine(ds.Tables[0].Rows[0][0]);
E agora tenho o serviço publicado em ASMX e o consumo utilizando a parte cliente desta mesma tecnologia. Agora decidi mudar o lado do servidor para WCF. Para isso, eu criei a seguinte estrutura:
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(Servico), new Uri[] { }))
{
host.AddServiceEndpoint(typeof(IContrato), new BasicHttpBinding(), "http://localhost:51982/Service1.asmx");
host.Open();Console.WriteLine("rodando..");
Console.ReadLine();
}
}
}[ServiceContract]
interface IContrato
{
[OperationContract]
DataSet HelloWorld();
}public class Servico : IContrato
{
public DataSet HelloWorld()
{
DataSet ds = new DataSet();
DataTable dt = new DataTable();
dt.Columns.Add("Nome");
dt.Rows.Add("Israel");ds.Tables.Add(dt);
return ds;
}
}
Só que quando rodei desta forma, obtive o seguinte problema:
Unhandled Exception: System.Web.Services.Protocols.SoapHeaderException: The mess
age with Action 'http://tempuri.org/HelloWorld' cannot be processed at the recei
ver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be bec
ause of either a contract mismatch (mismatched Actions between sender and receiv
er) or a binding/security mismatch between the sender and the receiver. Check t
hat sender and receiver have the same contract and the same binding (including s
ecurity requirements, e.g. Message, Transport, None).
Como havia dito, o problema está na SOAPAction, o que me obrigou a mudar um detalhe no contrato, que foi a customização da propriedade Action:
[ServiceContract]
interface IContrato
{
[OperationContract(Action = "http://tempuri.org/HelloWorld")]
DataSet HelloWorld();
}
http://www.israelaece.com- Marcado como Resposta Pedro Henrique Macedo de Souza quinta-feira, 2 de setembro de 2010 13:06
Todas as Respostas
-
Boas Pedro,
Como está a configuração do serviço que você está expondo para os clientes?
http://www.israelaece.com -
-
Boas Pedro,
Eu fiz uma simulação aqui, e o problema pode estar sendo a SOAP Action.
Provavelmente o teu serviço ASMX publicava a action para a operação como algo sendo http://tempuri.org/TuaOperacaoAqui, só que o WCF inclui o nome do contrato, por exemplo: http://tempuri.org/IContrato/TuaOperacaoAqui
Então, tente definir explicitamente a ação através do atributo OperationContractAttribute, para manter compatibilidade com o ASMX:
[ServiceContract]
interface IContrato
{
[OperationContract(Action = "http://tempuri.org/TuaOperacaoAqui")]
string HelloWorld();
}
http://www.israelaece.com -
Olá Israel, tudo bem?
Mesmo alterando o Action com o parametro Action do atributo ainda está tendo a mensagem, e o engraçado que pela mensagem o contrato ainda está incluso, mesmo na referência não incluindo o contrato. Está abaixo o contrato:
[OperationContract(Action="http://tempuri.org/GetFormPag")]
System.Data.DataSet GetFormPag(int Codigo);
-
-
O meu WebService só está ultilizando autenticação via usuario e senha:
public class AuthHeader : SoapHeader { //<returns>string</returns> public string UserName; //<returns>string</returns> public string Password; } [AttributeUsage(AttributeTargets.Method)] public class AuthExtensionAttribute : SoapExtensionAttribute { int _priority = 1; public override int Priority { get { return _priority; } set { _priority = value; } } public override Type ExtensionType { get { return typeof(AuthExtension); } } } public class AuthExtension : SoapExtension { public override void ProcessMessage(SoapMessage message) { if (message.Stage == SoapMessageStage.AfterDeserialize) { string UserName = string.Empty; string UserPass = string.Empty; foreach (SoapHeader header in message.Headers) { if (header is AuthHeader) { AuthHeader credentials = (AuthHeader)header; UserName = credentials.UserName.ToUpper(); UserPass = credentials.Password.ToUpper(); if (UserName == "COMPUFORTE" && UserPass == "COMPUXPTO") return; break; } } throw new SoapException("Você não tem permissão para acessar esta aplicação." + UserName + " - " +UserPass, SoapException.ClientFaultCode); } } public override Object GetInitializer(Type type) { return GetType(); } public override Object GetInitializer(LogicalMethodInfo info, SoapExtensionAttribute attribute) { return null; } public override void Initialize(Object initializer) { } }
aí eu ultilizo nos metodos o AuthExtensionAttribute.
[AuthExtension] [SoapHeader("Credentials")] [WebMethod(Description = "Faz o Login do Usuário.", EnableSession = true)] public UserInformation.User Login(string UserName, string UserPass, string Terminal)
-
Boas Pedro,
E como estão os endereços? Você está substituindo para o WCF e mantendo o mesmo endereço?
http://www.israelaece.com -
Boas Pedro,
Para você ter uma ideia do que fiz aqui para reproduzir:
Crei uma aplicação ASP.NET Web Services (ASMX) com um único serviço, que está abaixo:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public DataSet HelloWorld()
{
DataSet ds = new DataSet();
DataTable dt = new DataTable();
dt.Columns.Add("Nome");
dt.Rows.Add("Israel");ds.Tables.Add(dt);
return ds;
}
}
Depois disso, rodei o serviço e ele foi publicado no seguinte endereço: http://localhost:51982/Service1.asmx. Com isso, fiz a referência para o mesmo em uma aplicação Windows para assim consumir. Depois da referência feita (utilizando a opção antiga, que é para referenciar serviços ASMX), eu escrevi o seguinte código para consumo:
Service1 s = new Service1();
DataSet ds = s.HelloWorld();
Console.WriteLine(ds.Tables[0].Rows[0][0]);
E agora tenho o serviço publicado em ASMX e o consumo utilizando a parte cliente desta mesma tecnologia. Agora decidi mudar o lado do servidor para WCF. Para isso, eu criei a seguinte estrutura:
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(Servico), new Uri[] { }))
{
host.AddServiceEndpoint(typeof(IContrato), new BasicHttpBinding(), "http://localhost:51982/Service1.asmx");
host.Open();Console.WriteLine("rodando..");
Console.ReadLine();
}
}
}[ServiceContract]
interface IContrato
{
[OperationContract]
DataSet HelloWorld();
}public class Servico : IContrato
{
public DataSet HelloWorld()
{
DataSet ds = new DataSet();
DataTable dt = new DataTable();
dt.Columns.Add("Nome");
dt.Rows.Add("Israel");ds.Tables.Add(dt);
return ds;
}
}
Só que quando rodei desta forma, obtive o seguinte problema:
Unhandled Exception: System.Web.Services.Protocols.SoapHeaderException: The mess
age with Action 'http://tempuri.org/HelloWorld' cannot be processed at the recei
ver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be bec
ause of either a contract mismatch (mismatched Actions between sender and receiv
er) or a binding/security mismatch between the sender and the receiver. Check t
hat sender and receiver have the same contract and the same binding (including s
ecurity requirements, e.g. Message, Transport, None).
Como havia dito, o problema está na SOAPAction, o que me obrigou a mudar um detalhe no contrato, que foi a customização da propriedade Action:
[ServiceContract]
interface IContrato
{
[OperationContract(Action = "http://tempuri.org/HelloWorld")]
DataSet HelloWorld();
}
http://www.israelaece.com -
Boas Pedro,
Para você ter uma ideia do que fiz aqui para reproduzir:
Crei uma aplicação ASP.NET Web Services (ASMX) com um único serviço, que está abaixo:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public DataSet HelloWorld()
{
DataSet ds = new DataSet();
DataTable dt = new DataTable();
dt.Columns.Add("Nome");
dt.Rows.Add("Israel");ds.Tables.Add(dt);
return ds;
}
}
Depois disso, rodei o serviço e ele foi publicado no seguinte endereço: http://localhost:51982/Service1.asmx. Com isso, fiz a referência para o mesmo em uma aplicação Windows para assim consumir. Depois da referência feita (utilizando a opção antiga, que é para referenciar serviços ASMX), eu escrevi o seguinte código para consumo:
Service1 s = new Service1();
DataSet ds = s.HelloWorld();
Console.WriteLine(ds.Tables[0].Rows[0][0]);
E agora tenho o serviço publicado em ASMX e o consumo utilizando a parte cliente desta mesma tecnologia. Agora decidi mudar o lado do servidor para WCF. Para isso, eu criei a seguinte estrutura:
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(Servico), new Uri[] { }))
{
host.AddServiceEndpoint(typeof(IContrato), new BasicHttpBinding(), "http://localhost:51982/Service1.asmx");
host.Open();Console.WriteLine("rodando..");
Console.ReadLine();
}
}
}[ServiceContract]
interface IContrato
{
[OperationContract]
DataSet HelloWorld();
}public class Servico : IContrato
{
public DataSet HelloWorld()
{
DataSet ds = new DataSet();
DataTable dt = new DataTable();
dt.Columns.Add("Nome");
dt.Rows.Add("Israel");ds.Tables.Add(dt);
return ds;
}
}
Só que quando rodei desta forma, obtive o seguinte problema:
Unhandled Exception: System.Web.Services.Protocols.SoapHeaderException: The mess
age with Action 'http://tempuri.org/HelloWorld' cannot be processed at the recei
ver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be bec
ause of either a contract mismatch (mismatched Actions between sender and receiv
er) or a binding/security mismatch between the sender and the receiver. Check t
hat sender and receiver have the same contract and the same binding (including s
ecurity requirements, e.g. Message, Transport, None).
Como havia dito, o problema está na SOAPAction, o que me obrigou a mudar um detalhe no contrato, que foi a customização da propriedade Action:
[ServiceContract]
interface IContrato
{
[OperationContract(Action = "http://tempuri.org/HelloWorld")]
DataSet HelloWorld();
}
http://www.israelaece.com- Marcado como Resposta Pedro Henrique Macedo de Souza quinta-feira, 2 de setembro de 2010 13:06