Quando olho para trás lembro-me de quando eu era um humilde padawan que queria ser um monge Jedi em Java, e lembro claramente dos conselheiros Jedi do RSJUG falando "vá pelo caminho da orientação a objetos".
Se passaram alguns muitos anos e eu ainda lembro e sou fiel a esse princípio, e quando vejo por aí classes ou entidades de banco de dados, que eu irei ter que transformar em classes¹, contendo 181 campos (não é piada!) minha gastrite quase me mata!
Eu não sei por que as pessoas teimam em ter campos como CPF, CNPJ, data de inicio e de fim, etc em certas classes.
A quem vai ficar destinada a tarefa de validar um CNPJ/CPF? Ou se a data de início não é maior do que a de fim? Não tenha receio de criar classes que não serão persistidas. As pessoas tem a imagem de que classes de domínio/modelo só devem existir se forem ser persistidas, o resto é classe útil, DAO, service, etc. e não é bem por aí.
É do domínio da minha aplicação um CNPJ/CPF! E eu tenho que ter um objeto para isso, com a responsabilidade de validar se ele mesmo é válido. Não vou jogar essa responsabilidade para uma classe megazord no pacote útil responsável por validar isso e, talvez, mais coisas em um único lugar (olha o acoplamento aíííííííí gente).
Bem, para exemplificar isso, vou mostrar um código/abordagem que gosto muito, onde eu separo o campo nome da classe usuário em um objeto a parte.
Se você parar para pensar, o nome deve conter sempre 3 campos: primeiro nome, inicial do meio e último(s) nome(s).
Mas e o usuário SISTEMA? Ele não tem sobrenome. E o John Doe que não tem nome do meio?
Então eu tenho a classe PersonName:
using System;
using System.Text;
namespace com.blogspot.jeanjmichel.model
{
public class PersonName
{
private String firstName;
private String middleInitial;
private String lastName;
public String FirstName
{
set { this.firstName = value; }
get { return this.firstName; }
}
public String MiddleInitial
{
set { this.middleInitial = value; }
get { return this.middleInitial; }
}
public String LastName
{
set { this.lastName = value; }
get { return this.lastName; }
}
public PersonName()
{
}
public PersonName(String firstName)
{
this.FirstName = firstName;
}
public PersonName(String firstName, String middleInitial,
String lastName)
{
this.FirstName = firstName;
this.MiddleInitial = middleInitial;
this.LastName = lastName;
}
public override String ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append(this.LastName);
sb.Append(", ");
sb.Append(this.FirstName);
sb.Append(" ");
sb.Append(this.MiddleInitial);
return sb.ToString();
}
}
}
E agora a classe User:
using System;
using System.Text;
namespace com.blogspot.jeanjmichel.model
{
public class User
{
#region attributes
Int64 id;
String username;
PersonName personName;
char gender;
String password;
char active;
#endregion
#region properties
public Int64 Id
{
set { this.id = value; }
get { return this.id; }
}
public String Username
{
set { this.username = value; }
get { return this.username; }
}
public PersonName PersonName
{
set { this.personName = value; }
get { return this.personName; }
}
public char Gender
{
set { this.gender = value; }
get { return this.gender; }
}
public String Password
{
set { this.password = value; }
get { return this.password; }
}
public char Active
{
set { this.active = value; }
get { return this.active; }
}
#endregion
/// <summary>
/// Returns a string with this instance's data
/// The format of the string is:
/// namespace + class name + [ + the fields most representative
/// of the class + ].
/// </summary>
/// <returns>Returns a string with this instance's data</returns>
public override String ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append("com.blogspot.jeanjmichel.model.User [");
sb.Append(this.PersonName);
sb.Append(" as '");
sb.Append(this.Username);
sb.Append("'");
sb.Append(" Active: ");
sb.Append(this.Active);
sb.Append("]");
return sb.ToString();
}
public User()
{
}
public User(String username, PersonName personName, String password,
char active)
{
this.Username = username;
this.PersonName = personName;
this.Password = password;
this.Active = active;
}
public User(Int64 id, String username, PersonName personName,
char gender, String password, char active)
{
this.Id = id;
this.Username = username;
this.PersonName = personName;
this.Gender = gender;
this.Password = password;
this.Active = active;
}
}
}
Agora criando um usuário:
using System;
using com.blogspot.jeanjmichel.model;
namespace com.blogspot.jeanjmichel
{
class Program
{
static void Main(string[] args)
{
PersonName pn = new PersonName("Jean", "J", "Michel");
User u = new User("jmichel", pn, "Senha", 'Y');
Console.WriteLine(u);
Console.ReadKey();
}
}
}
A saída é: com.blogspot.jeanjmichel.model.User [Michel, Jean J as 'jmichel' Active: Y].
Quase tudo funcionou.
Mas no teste unitário quando eu digo que criando o usuário System assim:
using System;
using com.blogspot.jeanjmichel.model;
namespace com.blogspot.jeanjmichel
{
class Program
{
static void Main(string[] args)
{
PersonName pn = new PersonName("System");
User u = new User("sysadmin", pn, "Senha", 'Y');
Console.WriteLine(u);
Console.ReadKey();
}
}
}
Eu espero o resultado: com.blogspot.jeanjmichel.model.User [System as 'sysadmin' Active: Y] o que acontece?
Failed TestUserToStringMethod TestProject Assert.AreEqual failed.
Expected:<com.blogspot.jeanjmichel.model.User [System as 'sysadmin' Active: Y]>.
Actual..:<com.blogspot.jeanjmichel.model.User [, System as 'sysadmin' Active: Y]>.
Holly crap! Então, a resposabilidade da minha classe PersonName é validar esse tipo de coisa. Refatorando-a teremos:
using System;
using System.Text;
namespace com.blogspot.jeanjmichel.model
{
public class PersonName
{
private String firstName;
private String middleInitial;
private String lastName;
public String FirstName
{
set { this.firstName = value; }
get { return this.firstName; }
}
public String MiddleInitial
{
set { this.middleInitial = value; }
get { return this.middleInitial; }
}
public String LastName
{
set { this.lastName = value; }
get { return this.lastName; }
}
public PersonName()
{
}
public PersonName(String firstName)
{
this.FirstName = firstName;
}
public PersonName(String firstName, String middleInitial,
String lastName)
{
this.FirstName = firstName;
this.MiddleInitial = middleInitial;
this.LastName = lastName;
}
public override String ToString()
{
StringBuilder sb = new StringBuilder();
if (String.IsNullOrEmpty(this.LastName))
{
sb.Append(this.FirstName);
}
else
{
sb.Append(this.LastName);
sb.Append(", ");
sb.Append(this.FirstName);
sb.Append(String.IsNullOrEmpty(this.MiddleInitial) ? "" :
" " + this.MiddleInitial);
}
return sb.ToString();
}
}
}
Eu faço o mesmo com CNPJ/CPF, datas (eu crio uma classe chamada período) e outras.
¹ Eu não criei uma classe com 181 campos, mas também não pude refatorar a classe, a tabela, etc (software de terceiros). então criei uma classe com o set mínimo de informações da tabela, que deu mais de 30 campos, e faço o enxerto do resto com os valores padrão para cada campo. Uma pena eu não poder quebrar essa maldita tabela em meia dúzia de 8 tabelas mais produtivas e reutilizáveis. Enfim, coisas da TI que o McGyver aprovaria :)
quarta-feira, outubro 23, 2013
Não deixe o básico da orientação a objetos de lado, nunca!
Marcadores:
.net,
acoplamento,
análise orientada a objetos,
c#,
java,
lo,
orientação a objetos,
responsabilidade
terça-feira, outubro 08, 2013
Utilizando métodos seguros no WCF
Recentemente estive trabalhando com o WCF (Windows Communication Foundation) da Microsoft. E depois de fazer algumas experiências básicas lá fui eu me certificar da forma de transmissão segura e criptografadas.
Não vou me alongar na explicação porque isso tem no MSDN e em n blogs melhores escritor do que o meu :-), mas, como de praxe vou registrar um exemplo aqui (cabe ressaltar que daria para refatorar um pouco esse meu exemplo, que eu tive que fazer as pressas, principalmente a classe Greetting.cs que ficou bem porca mesmo. Admito, sem orgulho :-| #ficaAdica).
Para quem não sabe o que é o WCF, aqui vai a definição da Microsoft:
Windows Communication Foundation (WCF) is Microsoft's unified programming model for building service-oriented applications. It enables developers to build secure, reliable, transacted solutions that integrate across platforms and interoperate with existing investments.
Sacou?
Então vamos ao que interessa: código!
Em meu exemplo eu criei uma classe chamada Credential.cs que irá armazenar um token (que no meu caso é uma senha) e a informação de que tipo de device está consumindo meu serviço.
Além disso, há uma classe onde a lógica do meu programa está implementada e outra classe que é o serviço em sí (a lógica do tratamento das chamadas ao serviço).
Simplão, o funcionamento é: conferir se a senha passada está correta e se estiver chamar a classe que vai gerar a saudação e retorná-la ao client, caso contrário é lançar uma exceção.
Para começar essa é a classe da credencial (Credential.cs):
using System;
using System.ServiceModel;
using System.Net.Security;
namespace com.blogspot.jeanjmichel.services
{
/// <summary>
/// This class represents the credential.
/// </summary>
[MessageContract]
public class Credential
{
/// <summary>
/// The token is a password that have be valid to authorize the
/// client to consume the service.
/// </summary>
[MessageHeader(ProtectionLevel = ProtectionLevel.EncryptAndSign)]
public String Token;
/// <summary>
/// The DeviceCategory is an inrelevant information that is not
/// encrypted and is just used to show the kind of device is
/// consuming the service (Whindows Phone, iOS, Android, web page,
/// etc).
/// </summary>
[MessageBodyMember(Order = 1, ProtectionLevel = ProtectionLevel.None)]
public String DeviceCategory;
/// <summary>
/// Empty constructor.
/// </summary>
public Credential()
{
}
}
}
Notem que a informação do token irá trafegar criptografada, no header da mensagem. Já a informação do device do client não irá trafegar criptografada.
Greeting.cs, este é o core, ou kernel, do programa, dependendo do quanto nojento você queira parecer falando isso :-) (roubei essa do Elemar Jr):
using System;
using System.ServiceModel;
using System.Net.Security;
namespace com.blogspot.jeanjmichel.model
{
/// <summary>
/// This class represents a greeting.
/// </summary>
[MessageContract]
public class Greeting
{
private String userGreeting;
/// <summary>
/// This method will set an appropriate greeting based on the server's
/// local time.
/// </summary>
private void SetGreeting()
{
DateTime now = DateTime.Now;
if (now.Hour >= 7 && now.Hour <= 11)
{
this.userGreeting = "Good morning";
}
else if (now.Hour >= 12 && now.Hour <= 17)
{
if (now.Hour == 12 || now.Hour == 13)
{
this.userGreeting = "Good afternoon, it's lunch time!";
}
else
{
this.userGreeting = "Good afternoon";
}
}
else if (now.Hour >= 18 && now.Hour <= 20)
{
this.userGreeting = "Good evening";
}
else
{
this.userGreeting = "Good night";
}
}
/// <summary>
/// This property returns the greeting in the message body,
/// and this will move across the network ever encrypted.
/// </summary>
[MessageBodyMember(Order = 1, ProtectionLevel = ProtectionLevel.EncryptAndSign)]
public String UserGreeting
{
get { return this.userGreeting; }
}
/// <summary>
/// Empty constructor.
/// </summary>
public Greeting()
{
this.SetGreeting(); //Call the method on construction time.
}
}
}
Fica a dica para quem quiser refatorar essa classe: usar internacionalização para retornar a saudação em n idiomas.
E por fim, mas não menos importante :-), a interface (contrato) do serviço e a implementação dele:
using System.ServiceModel;
using com.blogspot.jeanjmichel.model;
namespace com.blogspot.jeanjmichel.services.contract
{
/// <summary>
/// This interface defines the service methods.
/// </summary>
[ServiceContract(Namespace = "http://jeanjmichel.blogspot.com/services/v0.0.1")]
public interface IGetGreeting
{
/// <summary>
/// This method will returns a greeting based based on the server's
/// local time.
/// </summary>
/// <param name="credential">An access credential that will be validated
/// in order to authorize the access to the
/// method.</param>
/// <returns>A Greeting object.</returns>
[OperationContract]
Greeting GetGreeting(Credential credential);
}
}
using System;
using System.ServiceModel;
using com.blogspot.jeanjmichel.services.contract;
using com.blogspot.jeanjmichel.model;
namespace com.blogspot.jeanjmichel.services
{
/// <summary>
/// This class is the service. Is where the logic behind the services'
/// calls occurs (validade credencial, invoke the business layer, etc).
/// </summary>
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
Namespace = "http://jeanjmichel.blogspot.com/services/v0.0.1")]
public class GetGreetingService: IGetGreeting
{
/// <summary>
/// This method will returns a greeting based based on the server's
/// local time.
/// </summary>
/// <param name="credential">An access credential that will be validated
/// in order to authorize the access to the
/// method.</param>
/// <returns>A Greeting object.</returns>
public Greeting GetGreeting(Credential credential)
{
if (String.IsNullOrEmpty(credential.Token))
{
throw new FaultException("Inform the security phrase," +
" and try again.");
}
else
{
if (credential.Token.Equals("mySeCuriTyP@ss"))
{
Greeting g = new Greeting();
return g;
}
else
{
throw new FaultException("Wrong password.");
}
}
}
}
}
Só falta configurar a aplicação no app.config, na tag <endpoint> o atributo binding de basicHttpBinding por wsHttpBinding:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="GetGreetingService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8081/soa" />
</baseAddresses>
</host>
<endpoint address =""
binding="wsHttpBinding"
contract="com.blogspot.jeanjmichel.services.contract.IGetGreeting"
bindingNamespace="http://jeanjmichel.blogspot.com/services/v0.0.1" >
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<useRequestHeadersForMetadataAddress>
<defaultPorts>
<add scheme="http" port="8010" />
</defaultPorts>
</useRequestHeadersForMetadataAddress>
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Agora o client para consumir o serviço:
using ConsoleClient.GetGreetingService; using System; using System.ServiceModel; namespace ConsoleClient { public class Program { static void Main(string[] args) { Console.WriteLine("Connecting to the endpoint..."); ChannelFactory<IGetGreeting> factory = new ChannelFactory<IGetGreeting>("WSHttpBinding_IGetGreeting", new EndpointAddress("http://192.168.0.173:8081/soa/GetGreetingService.svc")); Console.WriteLine("Creating the proxy..."); IGetGreeting proxy = factory.CreateChannel(); Console.WriteLine("Creating the credential..."); Credential credential = new Credential(); credential.Token = "mySeCuriTyP@ss"; credential.DeviceCategory = "Windows Phone 7.8"; try { Console.WriteLine("Call the service..."); Greeting greeting = proxy.GetGreeting(credential); Console.WriteLine("Greeting: " + greeting.UserGreeting); } catch (Exception e) { Console.WriteLine("An error has occurred. Message: " + e.Message); } Console.ReadKey(); } } }
Rodando esse client assim como está aqui a saída seria:
Connecting to the endpoint... Creating the proxy... Creating the credential... Call the service... Greeting: Good evening
Se você errar a senha:
Connecting to the endpoint... Creating the proxy... Creating the credential... Call the service... An error has occurred. Message: Wrong password.
E se você anular a senha:
Connecting to the endpoint... Creating the proxy... Creating the credential... Call the service... An error has occurred. Message: Inform the security phrase, and try again.
Vale ressaltar que eu estou hospedando a aplicação em um IIS local para testes.
Era isso. Qualquer dúvida é só comentar.
Não vou me alongar na explicação porque isso tem no MSDN e em n blogs melhores escritor do que o meu :-), mas, como de praxe vou registrar um exemplo aqui (cabe ressaltar que daria para refatorar um pouco esse meu exemplo, que eu tive que fazer as pressas, principalmente a classe Greetting.cs que ficou bem porca mesmo. Admito, sem orgulho :-| #ficaAdica).
Para quem não sabe o que é o WCF, aqui vai a definição da Microsoft:
Windows Communication Foundation (WCF) is Microsoft's unified programming model for building service-oriented applications. It enables developers to build secure, reliable, transacted solutions that integrate across platforms and interoperate with existing investments.
Sacou?
Então vamos ao que interessa: código!
Em meu exemplo eu criei uma classe chamada Credential.cs que irá armazenar um token (que no meu caso é uma senha) e a informação de que tipo de device está consumindo meu serviço.
Além disso, há uma classe onde a lógica do meu programa está implementada e outra classe que é o serviço em sí (a lógica do tratamento das chamadas ao serviço).
Simplão, o funcionamento é: conferir se a senha passada está correta e se estiver chamar a classe que vai gerar a saudação e retorná-la ao client, caso contrário é lançar uma exceção.
Para começar essa é a classe da credencial (Credential.cs):
using System;
using System.ServiceModel;
using System.Net.Security;
namespace com.blogspot.jeanjmichel.services
{
/// <summary>
/// This class represents the credential.
/// </summary>
[MessageContract]
public class Credential
{
/// <summary>
/// The token is a password that have be valid to authorize the
/// client to consume the service.
/// </summary>
[MessageHeader(ProtectionLevel = ProtectionLevel.EncryptAndSign)]
public String Token;
/// <summary>
/// The DeviceCategory is an inrelevant information that is not
/// encrypted and is just used to show the kind of device is
/// consuming the service (Whindows Phone, iOS, Android, web page,
/// etc).
/// </summary>
[MessageBodyMember(Order = 1, ProtectionLevel = ProtectionLevel.None)]
public String DeviceCategory;
/// <summary>
/// Empty constructor.
/// </summary>
public Credential()
{
}
}
}
Notem que a informação do token irá trafegar criptografada, no header da mensagem. Já a informação do device do client não irá trafegar criptografada.
Greeting.cs, este é o core, ou kernel, do programa, dependendo do quanto nojento você queira parecer falando isso :-) (roubei essa do Elemar Jr):
using System;
using System.ServiceModel;
using System.Net.Security;
namespace com.blogspot.jeanjmichel.model
{
/// <summary>
/// This class represents a greeting.
/// </summary>
[MessageContract]
public class Greeting
{
private String userGreeting;
/// <summary>
/// This method will set an appropriate greeting based on the server's
/// local time.
/// </summary>
private void SetGreeting()
{
DateTime now = DateTime.Now;
if (now.Hour >= 7 && now.Hour <= 11)
{
this.userGreeting = "Good morning";
}
else if (now.Hour >= 12 && now.Hour <= 17)
{
if (now.Hour == 12 || now.Hour == 13)
{
this.userGreeting = "Good afternoon, it's lunch time!";
}
else
{
this.userGreeting = "Good afternoon";
}
}
else if (now.Hour >= 18 && now.Hour <= 20)
{
this.userGreeting = "Good evening";
}
else
{
this.userGreeting = "Good night";
}
}
/// <summary>
/// This property returns the greeting in the message body,
/// and this will move across the network ever encrypted.
/// </summary>
[MessageBodyMember(Order = 1, ProtectionLevel = ProtectionLevel.EncryptAndSign)]
public String UserGreeting
{
get { return this.userGreeting; }
}
/// <summary>
/// Empty constructor.
/// </summary>
public Greeting()
{
this.SetGreeting(); //Call the method on construction time.
}
}
}
Fica a dica para quem quiser refatorar essa classe: usar internacionalização para retornar a saudação em n idiomas.
E por fim, mas não menos importante :-), a interface (contrato) do serviço e a implementação dele:
using System.ServiceModel;
using com.blogspot.jeanjmichel.model;
namespace com.blogspot.jeanjmichel.services.contract
{
/// <summary>
/// This interface defines the service methods.
/// </summary>
[ServiceContract(Namespace = "http://jeanjmichel.blogspot.com/services/v0.0.1")]
public interface IGetGreeting
{
/// <summary>
/// This method will returns a greeting based based on the server's
/// local time.
/// </summary>
/// <param name="credential">An access credential that will be validated
/// in order to authorize the access to the
/// method.</param>
/// <returns>A Greeting object.</returns>
[OperationContract]
Greeting GetGreeting(Credential credential);
}
}
using System;
using System.ServiceModel;
using com.blogspot.jeanjmichel.services.contract;
using com.blogspot.jeanjmichel.model;
namespace com.blogspot.jeanjmichel.services
{
/// <summary>
/// This class is the service. Is where the logic behind the services'
/// calls occurs (validade credencial, invoke the business layer, etc).
/// </summary>
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
Namespace = "http://jeanjmichel.blogspot.com/services/v0.0.1")]
public class GetGreetingService: IGetGreeting
{
/// <summary>
/// This method will returns a greeting based based on the server's
/// local time.
/// </summary>
/// <param name="credential">An access credential that will be validated
/// in order to authorize the access to the
/// method.</param>
/// <returns>A Greeting object.</returns>
public Greeting GetGreeting(Credential credential)
{
if (String.IsNullOrEmpty(credential.Token))
{
throw new FaultException("Inform the security phrase," +
" and try again.");
}
else
{
if (credential.Token.Equals("mySeCuriTyP@ss"))
{
Greeting g = new Greeting();
return g;
}
else
{
throw new FaultException("Wrong password.");
}
}
}
}
}
Só falta configurar a aplicação no app.config, na tag <endpoint> o atributo binding de basicHttpBinding por wsHttpBinding:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="GetGreetingService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8081/soa" />
</baseAddresses>
</host>
<endpoint address =""
binding="wsHttpBinding"
contract="com.blogspot.jeanjmichel.services.contract.IGetGreeting"
bindingNamespace="http://jeanjmichel.blogspot.com/services/v0.0.1" >
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<useRequestHeadersForMetadataAddress>
<defaultPorts>
<add scheme="http" port="8010" />
</defaultPorts>
</useRequestHeadersForMetadataAddress>
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Agora o client para consumir o serviço:
using ConsoleClient.GetGreetingService; using System; using System.ServiceModel; namespace ConsoleClient { public class Program { static void Main(string[] args) { Console.WriteLine("Connecting to the endpoint..."); ChannelFactory<IGetGreeting> factory = new ChannelFactory<IGetGreeting>("WSHttpBinding_IGetGreeting", new EndpointAddress("http://192.168.0.173:8081/soa/GetGreetingService.svc")); Console.WriteLine("Creating the proxy..."); IGetGreeting proxy = factory.CreateChannel(); Console.WriteLine("Creating the credential..."); Credential credential = new Credential(); credential.Token = "mySeCuriTyP@ss"; credential.DeviceCategory = "Windows Phone 7.8"; try { Console.WriteLine("Call the service..."); Greeting greeting = proxy.GetGreeting(credential); Console.WriteLine("Greeting: " + greeting.UserGreeting); } catch (Exception e) { Console.WriteLine("An error has occurred. Message: " + e.Message); } Console.ReadKey(); } } }
Rodando esse client assim como está aqui a saída seria:
Connecting to the endpoint... Creating the proxy... Creating the credential... Call the service... Greeting: Good evening
Se você errar a senha:
Connecting to the endpoint... Creating the proxy... Creating the credential... Call the service... An error has occurred. Message: Wrong password.
E se você anular a senha:
Connecting to the endpoint... Creating the proxy... Creating the credential... Call the service... An error has occurred. Message: Inform the security phrase, and try again.
Vale ressaltar que eu estou hospedando a aplicação em um IIS local para testes.
Era isso. Qualquer dúvida é só comentar.
Marcadores:
serviços,
soa,
soap,
wcf,
webservices,
windows communication foundation
sexta-feira, outubro 04, 2013
Problema para usar o OpenId do wordpress.com
Semana passada estava
tentando logar no http://www.stackoverflow.com usando a minha conta do http://www.wordpress.com (o
OpenId). Mas o que eu conseguia mesmo era um erro dizendo "You do not own that
identity". Como assim? Quer dizer que eu não sou eu?
Na verdade o que ocorria é que meu usuário não era o mesmo da minha URL (eu já tinha o blog http://www.anonymousbiker. wordpress.com) no http://www.wordpress.com,
então dava esse erro bizarro. Eu tive que criar o blog http://www.jeanjmichel. wordpress.com para poder usar o
OpenId.
Fica a dica.
Na verdade o que ocorria é que meu usuário não era o mesmo da minha URL (eu já tinha o blog http://www.anonymousbiker.
Fica a dica.
Assinar:
Postagens (Atom)