Parameters & Messages
Transfer data via WCF we have 3 ways
-Parameters (general way)
-Example:
[DataContract]
public class Employee
{
private string m_Name;
private int m_Age;
private int m_Salary;
private string m_Designation;
private string m_Manager;
[DataMember]
public string Name
{
get { return m_Name; }
set { m_Name = value; }
}
[DataMember]
public int Age
{
get { return m_Age; }
set { m_Age = value; }
}
-Need to define [DataContract], [DataMember], and need serialization
-Typed Message
[MessageContract(Action="..")]
class AddRequestMessage
{
publicAddRequestMessage(){}
[MessageBody(Name="MyBody",Namespace="..")]
public AddRequest MyRequest {get;set;}
[MessageHeader(Name="MyHeader",Namespace="...")]
public int TimeToLive;
}
[MessageContract(Action="..")]
classAddResonMEssage
{
public AddResonMEssage(){}
[MessageBody]
public int Result{get;set;}
}
[ServiceContract]
[OpeationContract]
AddResponseMessageAddTwoNumber(AddRequestMessage a)
-UnTypedMessage : deal with soap message directly
[ServiceContract]
interfaceIAddTwoNumbers
{
[OpeartionContract]
MessageAddTwoNumbers(Message request);
}
Binding
-Predefine the channels
for example: if we change binding "basicHttpBinding" to "wsHttpBinding" or "netTcpBinding", the transmitted message will be different, "wsHttpBinding" will have some security element
-Tweak standard binding via bindingConfiguration
-security mode
-messageencoding
-Custom bindings
for example: you may not need message encoding, you may not need security etc.
Serialization
the data want to transfer over network, we need serialization
-Binaryseraizlabtion via [Serializable]
-private&public property will be seraizble
-you can define "[NonSeriazed]" to omit property to be serialized
-if want to custom serilaztion process, you can implement ISerialble
-for example:
[Serializable()] //Set this attribute to all the classes that want to serialize
public class Employee : ISerializable //derive your class from ISerializable
{
public int EmpId;
public string EmpName;
//Default constructor
public Employee()
{
EmpId = 0;
EmpName = null;
}
}
public class Person:ISerializable
{
private string _FirstName;
private string _LastName;
public string FirstName
{
get { return _FirstName; }
set { _FirstName = value; }
}
public string LastName
{
get { return _LastName; }
set { _LastName = value; }
}
public Person()
{
}
public Person(string FirstName, string LastName)
{
this.FirstName = FirstName;
this.LastName = LastName;
}
void ISerializable.GetObjectData(SerializationInfo oInfo, StreamingContext oContext)
{
oInfo.AddValue("FirstName", this.FirstName);
oInfo.AddValue("LastName", this.LastName);
}
}
-XMLSerialization via [XmlRoot("MyClass")]
-[XmlAttribute("FirstName")]
-only serialize public type
-if want to custom serilaztion process, implement IXMlSeriazation
-for example:
[XmlRoot("XmlDocRoot")]
public class RootClass {
private int attribute_id;
[XmlAttribute("id")]
public int Id {
get { return attribute_id; }
set { attribute_id = value; }
}
}
public class Animal : IXmlSerializable
{
public Animal() { }
public String Name { get; set; }
public DateTime Birthday { get; set; }
public System.Xml.Schema.XmlSchema GetSchema() { return null; }
public void ReadXml(System.Xml.XmlReader reader)
{
reader.MoveToContent();
Name = reader.GetAttribute("Name");
Boolean isEmptyElement = reader.IsEmptyElement; // (1)
reader.ReadStartElement();
if (!isEmptyElement) // (1)
{
Birthday = DateTime.ParseExact(reader.
ReadElementString("Birthday"), "yyyy-MM-dd", null);
reader.ReadEndElement();
}
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteAttributeString("Name", Name);
if (Birthday != DateTime.MinValue)
writer.WriteElementString("Birthday",
Birthday.ToString("yyyy-MM-dd"));
}
}
-Stand Way via [DataContract]
-[DataMember]
DataContract Serialization
- we can define name & namespace
-if we dont expected client pass less information : Isrequired=true
-if we allow client pass more information: IExtensibleDataObject
-if we have dependency between properties: Serialization order : "Order=1"
-we can add method to execute after serialized
[OnSerialized]
-privatevoid AfterSerialized(StreamingContext ctx)
- we can add method to execute after de-serialized
[OnDeserialized]
-privatevoid AfterDeSerailized(StreamingContext ctx)
-dc.exe tocovert xml schema to data contract class
- for example:
[DataContract]
public class Customer : IExtensibleDataObject
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Address { get; set; }
[DataMember]
public int Salary { get; set; }
[DataMember]
public int NewSalary { get; set; }
public ExtensionDataObject ExtensionData { get; set; }
}
MessageEncoding
-Text
-MTOM
-Binnary
-CustomBinding
<customBinding>
<binding name="NetHttpBinding">
<binaryMessageEncoding />
<httpsTransport />
</binding>
</customBinding>
Message Pattern
-One way communication:[OperationContract(IsOneWay=true)]
-Client not need to wait serive return
-Duplexcommunication:[ServiceContract(CallbackContract=typeof(IPrntConfirmation)]
-Client need to implement "IMyContractCallback", and service will able to callback later
-e.g.:
Service:
interface IMyContractCallback
{
[OperationContract]
void OnCallback();
}
[ServiceContract(CallbackContract = typeof(IMyContractCallback))]
interface IMyContract
{
[OperationContract]
void DoSomething();
}
Client
class MyCallback : IMyContractCallback
{
public void OnCallback() {...}
}
IMyContractCallback callback = new MyCallback();
InstanceContext context = new InstanceContext(callback);
MyContractClient proxy = new MyContractClient(context);
proxy.DoSomething();
Https Transport Security
-Security Features
-Authorisation
-Auditing
-TransferSercurity
-Authentication
-Integrity
-Privacy
Above 3 features is achived by the following two technology:
-TransportSecurity (HTTPS)
-MessageSecurity (WS-Security)
Steps to use transport Security:
-1. Certificate
-Add certificate to "Trusted Root Certification Authorizor"
-Add cerfiticate to Https that listen port 9090:cmd>>httpcfg.exe set ssl -i0.0.0.0:9090 -h XXXX(cert thumbprint)
-2. endpoint:address set to "https"
-3. update bindingConfiguration
-securitymode="Transport"
-OR security mode="TransportWithMessageCredentail"/>
-How to identify client: Ask user name /password before Client can request go through traffic
-option 1: Add<transport clientCredentialsType="Basic"/>:windows basic authentication
-option 2: OR<transport clientCredentialsType="Digest"/>
-option 3: OR<transport clientCredentialsType="Windows"/>:default get therunning process authentication
-option 4: OR<transport clientCredentialsType="Certificate"/>
-option 5: OR-<tranport clientCredentailsType="Certificate"/>
+ <messageclientCredentailType="UserName"/>
Client Code:
-option 1:
proxy.ClientCredentails.UserNamePassword.UserName=""
proxy.ClientCredentails.UserNamePassword.Password=""
-option 2:
proxy.ClientCredentails.ImpersonationLevel=TokenImpersonationLevel.Impersonation
proxy.ClientCredentails.Digest.ClientCredentail=newNetworkCredentail("username,"password")
-option 3:
proxy.ClientCredentails.Windows.ClientCredentail=newNetworkCredentail("username,"password")
-option 4:
-add client certificate to server machine "trusted Root CertificationAuthorities"
-Clientside
-behaviorConfiguration
-<clientCredentials>
<clientCertificatestore Name="My" storeLocation="CurrentUser"x509FindType="xx"
findValue="xxx"/>
-option 5:
proxy.ClientCredentails.UserNamePassword.UserName=""
proxy.ClientCredentails.UserNamePassword.Password=""
+option 4
Message Security
-TransportLevel Security: Transport Security
-SOAP LevelSecurity: Message Security use (WS-Security features), inside SOAP Message
-except basicHttpBinding, other binding by default, send security information toservice, by default is windows security information
-<security mode="Message">
-option1 : <message clientCredentialType="Windows">
-option2: <message clientCredentialType="UserName">
+servicebehavior - to encode username to transfer via network
-<serviceCredetntails>
-<serviceCertificatex509FindType="" storeLocation="" storeName="
findValue=""
-option3: <message clientCredentailType="Certificate">
+servicebehavior
-<clientCredentails>
-Client Code
-option1 :
proxy.ClientCredentails.Windows.ClientCredentail=newNetworkCredentail("username,"password")
-option2 :
proxy.ClientCredentails.UserNamePassword.UserName=""
proxy.ClientCredentails.UserNamePassword.Password=""
+clientbehavior: to encode the username and password
-<clientCredentials>
-<serviceCertificate x509FindType="" storeLocation="" storeName="
findValue=""
-option3 :
<clientCredentials>
<clientCertificatestore Location="CurrentUser" StoreName=""...
-Custom "UserName" provider: not really need to link to windows account. we can create custom .net membership provider
+<servicebehavior>
-<serviceCredetntails>
-<serviceCertificatex509FindType="" storeLocation="" storeName="
findValue=""
<userNamePasswordmembershipProviderName="MyProvider"/>
-"defaultProtectionLevel"
<messageclientCredentialType=""
negotiateServiceCredentail="false"
defaultProtectionLevel="EncryptAndSign"/>
Concurrency
-ConcurrencyMode=ConcurrencyMode.Single
ConcurrencyMode.Multiple
ConcurrencyMode.Reentrant
Instancing
-InstanceContextMode=InstanceContextMode.PerCall
InstanceContextMode.PerSession
InstanceContextMode.Single
Sessions
[ServiceContract(SessionMode=SessionMode.Required)]
Client:string sessionId=OperationContext.Current.SessionIdentifier;
-[OperationContract(IsInitiating=true)]
-[OperationContract(IsInitiating=false)]
-[OperationContract(IsTerminating=true)]
Transaction
-if transaction cross process need a distribute transaction
-[OperationContract]
-[TransactionFlow(TransactionFlowOption.Allowed)]
+bindingConfiguration
<bindingtransactionFlow="true" transactionProtocal="oleTx"/>
-[TransactionFlow(TransactionFlowOption.NotAllowed)]
-[TransactionFlow(TransactionFlowOption.Required)]
[OpeartionBehavior(TransactionScopeRequired=true)]
using(TransactionScopescope =new TransactionScope(){
//ifalready has transaction then use it
//ifthere is no transaction then add new
}
Client Code:
using(TransactionScopescope=new TransactionScope()){
//Dosomething,proxy.aaa
//Dosomething,proxy.bbb
}
Exception
-why by default not send exception type and eception message, and not stack trace
-clientside may not understand .net exception
-forsome security risk
-[ServiceBehavior(includeExceptionDetailInFaults=true)]
-getting exception message, stack trace but not exception type
-[ServiceContract]
[FaultContract(typeof(InvalidOperationException))]
-getting exception type + exception message and stack trace
throw newFaultException<InvalidOperationException>(newInvalidOperationException(".."));
-Need custom process can implement :IErrorHandler
Authorisation
-option 1
-[OpeationContract]
-[PrincipalPermission(SecurityAction.Demand,Role="General User")]
-Not necessary to use windows group , we can use asp.net role management
-serviceBehavior
<serviceAuthoriaztionprincipalPermissionMode="UseAspNetRole"/>
-option 2
-Dynamicallyget current user role and make decisions
serviceSecurityContextctx=ServiceSecurityContext.Current;
-option 3
implement class CustomOperationRequirement: OperationRequirement
+<serviceAuthoriaztionprincipalPermissionMode="UseAspNetRole"opeationRequirementType="CustomOpeartionRequirement/>
Audit
-ServiceBehavior
-<serviceSecurityAudit
auditLogLocation="Application"
messageAuthenticationAuditLevel="SuccesOrFailure"
serviceAuthorizationAuditLevel="SuccesOrFailure"/>