My test indicates .NET Remoting is faster than WCF 4 by a factor of 1.5 - wcf

In order to tell whether my project should migrate from .net remoting to WCF, I extracted its network communication part and implemented it by WCF. I run the remoting version and wcf version and eventually find remoting is faster than wcf by a factor of 1.5, which greatly differs from the msdn article.
Test configuration
WCF and .NET Remoting both use tcp channel without encryption, no app.config file. Compiled in release mode, no optimization.
Operations
What my program does is this.
You can download the two solutions here.
WCF test
Service Host
ServiceHost host = new ServiceHost(typeof(Server), new Uri(string.Format("net.tcp://{0}:{1}/{2}", args[0], args[1], args[2])));
var binding = new NetTcpBinding();
binding.MaxReceivedMessageSize = 614400;
binding.ReaderQuotas.MaxArrayLength = 512000;//a max picture of 500KB
binding.Security.Mode = SecurityMode.None;
host.AddServiceEndpoint(typeof(IServer), binding, string.Empty);
host.Open();
Server
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single
//, IncludeExceptionDetailInFaults = true
, ConcurrencyMode = ConcurrencyMode.Reentrant
)]
public class Server : IServer
{
public EntryRequirement GetEntryRequirement()
{
return new EntryRequirement(new[] { "fuck", "sex" }, false);
}
public void AddClient()
{
var client = OperationContext.Current.GetCallbackChannel<IServerCallback>();
var p = client.Profile;
var x = client.Password;
System.Diagnostics.Debug.WriteLine(p);
System.Diagnostics.Debug.WriteLine(x);
}
}
Client side
Player player = new Player();
player.Password = "12423";
player.Profile = new Contracts.PlayerProfile
{
Description = "I'm a man.",
HeadImage = imageData,
Name = "Loveright"
};
var binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.None;
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 20; i++)
{
ServerProxy server = new ServerProxy(player, binding,
new EndpointAddress(string.Format("net.tcp://{0}:{1}/{2}", args[0], args[1], args[2])));
server.GetEntryRequirement();
server.AddClient();
}
watch.Stop();
HeadImage is a picture of size 139KB.
Player class
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
class Player : IServerCallback
{
public PlayerProfile Profile { get; set; }
public string Password { get; set; }
public void ClientCollectionChangedEventHandler(object sender, ControllersChangedEventArgs e)
{
}
public void ClientUpdatedEventHandler(object sender, ClientUpdatedEventArgs e)
{
}
}
.NET Remoting test
Host
var serverProv = new BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
var clientProv = new BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["port"] = args[1];
props["name"] = "tcp server";
var channel = new TcpChannel(props, clientProv, serverProv);
ChannelServices.RegisterChannel(channel, false);
System.Runtime.Remoting.RemotingConfiguration.RegisterWellKnownServiceType(typeof(Server),
args[2], System.Runtime.Remoting.WellKnownObjectMode.Singleton);
Client
var serverProv = new BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
var clientProv = new BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["name"] = "tcp client " + Guid.NewGuid();
props["port"] = 0;
var channel = new TcpChannel(props, clientProv, serverProv);
ChannelServices.RegisterChannel(channel, false);
FileStream stream = new FileStream(#"logotz6.png", FileMode.Open);
byte[] imageData = new byte[stream.Length];
stream.Read(imageData, 0, imageData.Length);
stream.Close();
Player player = new Player();
player.Password = "12423";
player.Profile = new PlayerProfile
{
Description = "I'm a man.",
HeadImage = imageData,
Name = "Loveright"
};
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 20; i++)
{
var serverProxy = (IServer)Activator.GetObject(typeof(IServer), string.Format("tcp://{0}:{1}/{2}", args[0], args[1], args[2]));
serverProxy.GetEntryRequirement();
serverProxy.AddClient(player);
}
watch.Stop();
You can download the two solutions here.
Result
So do I make the test somewhere unfair to WCF?

Should it be the message encoding king ?
Have you used binaryMessageEncoding instead of textMessageEncoding or soapMessageEncoding ?
You can create a custom binding to do this :
internal sealed class MyBinding : CustomBinding
{
private static readonly BindingElementCollection elementCollection;
static MyBinding()
{
MessageEncodingBindingElement encoding = new BinaryMessageEncodingBindingElement();
TcpTransportBindingElement transport = new TcpTransportBindingElement();
elementCollection = new BindingElementCollection();
elementCollection.Add(encoding);
elementCollection.Add(transport);
}
internal MyBinding(string bindingName, string bindingNamespace)
: base()
{
base.Namespace = bindingNamespace;
base.Name = bindingName;
}
public override BindingElementCollection CreateBindingElements()
{
return elementCollection;
}
}

Related

Why is WCF service not invoke when security is enabled on Async operations

When Security feature is enabled for Authencation using X509 certificate, Connecation to the server is not established. I find this issue when the client makes Async operation call. The code below works for synchronous operation. For instance if the call is made TrainHealth instead of BeginTrainHealth, the code works fine. As I understand, security is independent of whether operations are sync or async.
Any help on why this is not working is appreciated.
Contract :
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace = "http://www.bane.dk/services/fbane/2014/02/20", ConfigurationName = "Alstom.SmartBus.ESBBridge.ExternalIOPlugins.TrainData.TrainDataPort")]
public interface IStudentService
{
[System.ServiceModel.OperationContractAttribute(IsOneWay = true, AsyncPattern = false, Action = "TrainHealth")]
[System.ServiceModel.XmlSerializerFormatAttribute()]
void TrainHealth(int test);
[System.ServiceModel.OperationContractAttribute(IsOneWay = true, AsyncPattern = true, Action = "TrainHealth")]
[System.ServiceModel.XmlSerializerFormatAttribute()]
System.IAsyncResult BeginTrainHealth(int test, System.AsyncCallback callback, object asyncState);
void EndTrainHealth(System.IAsyncResult result);
}
Server Code :
class Program
{
static void Main(string[] args)
{
ServiceHost studentServiceHost = null;
try
{
//Base Address for StudentService
Uri httpBaseAddress = new Uri("https://10.107.64.33:5060/StudentService");
//Instantiate ServiceHost
studentServiceHost = new ServiceHost(typeof(StudentService), httpBaseAddress);
CustomBinding binding = CreateBinding();
ServiceEndpoint endpoint_GD = studentServiceHost.AddServiceEndpoint(typeof(IStudentService), binding, httpBaseAddress);
//Add Endpoint to Host
studentServiceHost.AddServiceEndpoint(typeof(IStudentService), binding, httpBaseAddress + "mex");
//Metadata Exchange
ServiceMetadataBehavior serviceBehavior = new ServiceMetadataBehavior();
serviceBehavior.HttpsGetEnabled = true;
studentServiceHost.Description.Behaviors.Add(serviceBehavior);
var behavior = studentServiceHost.Description.Behaviors.Find<ServiceDebugBehavior>();
behavior.IncludeExceptionDetailInFaults = true;
studentServiceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.PeerTrust;
studentServiceHost.Credentials.ClientCertificate.Authentication.TrustedStoreLocation = StoreLocation.LocalMachine;
studentServiceHost.Credentials.ServiceCertificate.SetCertificate(System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine, System.Security.Cryptography.X509Certificates.StoreName.My, System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName, "10.107.64.33");
ServiceSecurityAuditBehavior newAudit = new ServiceSecurityAuditBehavior();
newAudit.AuditLogLocation = AuditLogLocation.Application;
newAudit.MessageAuthenticationAuditLevel = AuditLevel.SuccessOrFailure;
newAudit.ServiceAuthorizationAuditLevel = AuditLevel.SuccessOrFailure;
newAudit.SuppressAuditFailure = false;
studentServiceHost.Description.Behaviors.Remove<ServiceSecurityAuditBehavior>();
studentServiceHost.Description.Behaviors.Add(newAudit);
studentServiceHost.Open();
Console.WriteLine("Service is live now at : {0}", httpBaseAddress);
Console.ReadKey();
}
catch (Exception ex)
{
studentServiceHost = null;
Console.WriteLine("There is an issue with StudentService" + ex.Message);
Console.ReadKey();
}
}
public static CustomBinding CreateBinding()
{
CustomBinding binding = new CustomBinding();
binding.Elements.Add(new ReliableSessionBindingElement());
TransportSecurityBindingElement sec = new TransportSecurityBindingElement();
binding.Elements.Add(sec);
binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11WSAddressing10, Encoding.UTF8));
binding.Elements.Add(new HttpsTransportBindingElement()
{
RequireClientCertificate = true
});
return binding;
}
}
Client Code :
class Program
{
static ChannelFactory<IStudentService> runTrainSvcCF = null;
static IStudentService runTrainSvcProxy;
static void Main(string[] args)
{
StartClient();
}
private static void StartClient()
{
EndpointAddress endPoint = new EndpointAddress(new Uri("https://10.107.64.33:5060/StudentService"), EndpointIdentity.CreateDnsIdentity("10.107.64.34"));
CustomBinding binding = CreateBinding();
runTrainSvcCF = new ChannelFactory<IStudentService>(binding, endPoint);
System.ServiceModel.Description.ClientCredentials credentials = runTrainSvcCF.Credentials;
credentials.ClientCertificate.SetCertificate(System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser,
System.Security.Cryptography.X509Certificates.StoreName.My,
System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName,
"10.107.64.34");
ServicePointManager.MaxServicePointIdleTime = 0;
credentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.PeerTrust;
ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(ValidateRemoteCertificate);
runTrainSvcProxy = runTrainSvcCF.CreateChannel();
try
{
runTrainSvcProxy.BeginTrainHealth(88, null, null);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static bool ValidateRemoteCertificate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate cert,
System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors policyErrors)
{
return true;
}
public static CustomBinding CreateBinding()
{
CustomBinding binding = new CustomBinding();
binding.Elements.Add(new ReliableSessionBindingElement());
binding.Elements.Add(new TransportSecurityBindingElement());
binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11WSAddressing10, Encoding.UTF8));
binding.Elements.Add(new HttpsTransportBindingElement()
{
RequireClientCertificate = true
});
return binding;
}
}

Passing list of object to Web API using RestSharp Client

I'm trying to send list of objects from MVC to WEBAPI using below methods. API is able to able receive the list from controller but, value of each item in the list is either empty/null on API side.
Can anyone please help me to fix this?
Controller Method:
private List<FCM.Models.Facility> GetFacilityDetails()
{
var url = "http://localhost:64664/";
var facilies = new List<Facility>();
facilies.Add( new Facility{ FCLT_ID = 100, FCLT_NM = "Facility 100" });
facilies.Add( new Facility{ FCLT_ID = 200, FCLT_NM = "Facility 200" });
facilies.Add( new Facility{ FCLT_ID = 300, FCLT_NM = "Facility 300" });
var json = JsonConvert.SerializeObject(facilies);
var _client = new RestClient(url);
var request = new RestRequest("api/facility/details", Method.GET) { RequestFormat = DataFormat.Json };
facilies.ForEach(fclt =>
request.AddParameter("facilites", fclt, ParameterType.GetOrPost));
var response = _client.Execute<List<FCM.Models.Facility>>(request);
if (response.Data == null)
{
throw new Exception(response.ErrorMessage);
}
return response.Data;
}
WebAPI method:
[Route("api/facility/details")]
public IEnumerable<Facility> GetFullAddress([FromUri] IEnumerable<Facility> facilities)
{
return null;
}
Like the comment suggested you maybe want to issue a POST request instead, but if you would like to send an array with a GETrequest you could do it like this (with System.Net.Http.HttpClient):
Add a Format method to you Facility class:
public class Facility
{
public int FCLT_ID { get; set; }
public string FCLT_NM { get; set; }
public string Format(int index)
{
return $"[{index}].FCLT_ID={FCLT_ID}&[{index}].FCLT_NM={FCLT_NM}";
}
}
Define a class which can format the array values:
public class FacilityList : List<Facility>
{
public string Format()
{
var builder = new StringBuilder();
for (var i = 0; i < Count; i++)
{
builder.Append(this[i].Format(i));
if(i != Count -1)
{
builder.Append("&");
}
}
return builder.ToString();
}
}
And then issue the request:
var client = new HttpClient()
{
BaseAddress = new Uri("http://localhost:64664/"),
DefaultRequestHeaders = {Accept = {new MediaTypeWithQualityHeaderValue("application/json")}}
};
var facilities = new FacilityList
{
new Facility {FCLT_ID = 100, FCLT_NM = "Facility 100"},
new Facility {FCLT_ID = 200, FCLT_NM = "Facility 200"},
new Facility {FCLT_ID = 300, FCLT_NM = "Facility 300"}
};
var format = facilities.Format();
var response = client.GetAsync("api/facility/details?" + format).GetAwaiter().GetResult();
var result = JsonConvert.DeserializeObject<IEnumerable<Facility>>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
This will bind to your controller action:
[Route("api/facility/details")]
public IHttpActionResult Get([FromUri] IEnumerable<Facility> facilities)
{
// Do stuff..
return Ok(facilities);
}

VCR for ServiceStack's JsonServiceClient

The Ruby VCR library enables you to "Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests."
I'd like to create something similar using ServiceStack's JsonServiceClient, but I can't get it to work. My most recent failed attempt follows. I'd like to either make my current attempt work, or suggestions on another approach that will work.
public static class Memoization
{
public static Func<T, TResult> AsCached<T, TResult>(this Func<T, TResult> function)
{
var cachedResults = new Dictionary<T, TResult>();
string filename = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + (typeof(TResult)).Name + ".jsv";
var serializer = MessagePackSerializer.Create<Dictionary<T, TResult>>();
if (cachedResults.Count == 0)
{
////// load cache from file
using (FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write))
{
cachedResults = serializer.Unpack(fs);
}
}
return (argument) =>
{
TResult result;
lock (cachedResults)
{
if (!cachedResults.TryGetValue(argument, out result))
{
result = function(argument);
cachedResults.Add(argument, result);
////// update cache file
using (FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write))
{
serializer.Pack(fs, cachedResults);
}
}
}
return result;
};
}
}
class MemoizeJsonClient<TResponse> : JsonServiceClient, IServiceClient, IRestClient
{
private Func<IReturn<TResponse>, TResponse> _getCached;
private JsonServiceClient client;
public TResponse Get(IReturn<TResponse> request)
{
if (_getCached == null)
{
Func<IReturn<TResponse>, TResponse> func = GetImpl;
_getCached = func.AsCached();
}
return _getCached(request);
}
private TResponse GetImpl(IReturn<TResponse> request)
{
return client.Get(request);
}
public MemoizeJsonClient(string BaseUri) {
client = new JsonServiceClient(BaseUri);
}
}
Called like this:
[Test]
public void TestReports2()
{
string Host = "http://localhost:1337";
string BaseUri = Host + "/";
List<Options> testcases = new List<Options>();
testcases.Add(new Options("Name", "20130815", "20130815"));
foreach (Options options in testcases)
{
TransactionsReq transRequest = new TransactionsReq();
transRequest.source = "Source";
transRequest.name = new List<String>(new string[] { options.Name });
transRequest.startDate = options.StartDate;
transRequest.endDate = options.EndDate;
MemoizeJsonClient<TransactionsReqResponse> client = new MemoizeJsonClient<TransactionsReqResponse>(BaseUri);
List<Transaction> transactions;
TransactionsReqResponse transResponse = client.Get(transRequest);
transactions = transResponse.data;
}
}
But I get the following error:
System.Runtime.Serialization.SerializationException occurred
HResult=-2146233076
Message=Cannot serialize type 'ServiceStack.ServiceHost.IReturn`1[ImagineServerWrapper.DTO.TransactionsReqResponse]' because it does not have any serializable fields nor properties.
Source=MsgPack
StackTrace:
at MsgPack.Serialization.SerializerBuilder`1.CreateSerializer()
InnerException:

how to access fields of deserialized object

I have a UDP client server application which is in c#, where the server sends the serialized object to client.
At the server end object is deserialized. Now my question is how can I access the fields or data members of the object?
Any suggestions or help would be appreciated.
Thanks
Vani
This is the server code which sends a object.
namespace UDP_Client
{
[Serializable]
class SendObject
{
public int a;
public int b;
public int c;
public SendObject()
{
a = 0;
b = 0;
c = 0;
}
}
class ClientSocket
{
static void Main(string[] args)
{
SendObject obj= new SendObject();
obj.a = 100;
obj.b = 200;
obj.c = 300;
MemoryStream memorystream = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(memorystream,obj);
Send(obj.ToString());
}
static void Send(string Message)
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress broadcast = IPAddress.Parse("127.0.0.1");
byte[] sendbuffer = Encoding.ASCII.GetBytes(Message);
IPEndPoint ep = new IPEndPoint(broadcast, 10000);
s.SendTo(sendbuffer, ep);
s.Close();
}
}
}
This is the client which receives the object coming from server.
UdpClient listener = new UdpClient(listenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, listenPort);
byte[] bytes = listener.Receive(ref groupEP);
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
stream.Seek(0, SeekOrigin.Begin);
Object obj = (Object)formatter.Deserialize(stream);
int val1 = obj.a;//This is what i want to do.

How to use IHttpCookieContainerManager in WCF 4.5

Just wanted to know how can we use IHttpCookieContainerManager in WCF 4.5. Suggest any sample code please.
In .NET 4.5 you can access the cookie container by using the .GetProperty().CookieContainer method like below if AllowCoookies = true.
Uri serverUri = new Uri("http://localhost/WcfService/Service1.svc");
CookieContainer myCookieContainer = new CookieContainer();
myCookieContainer.Add(serverUri, new Cookie("cookie1", "cookie1Value"));
ChannelFactory<IService1> factory = new ChannelFactory<IService1>(new BasicHttpBinding() { AllowCookies = true }, new EndpointAddress(serverUri));
IService1 client = factory.CreateChannel();
factory.GetProperty<IHttpCookieContainerManager>().CookieContainer = myCookieContainer;
Console.WriteLine(client.GetData(123));
myCookieContainer = factory.GetProperty<IHttpCookieContainerManager>().CookieContainer;
foreach (Cookie receivedCookie in myCookieContainer.GetCookies(serverUri))
{
Console.WriteLine("Cookie name : " + receivedCookie.Name + " Cookie value : " + receivedCookie.Value);
}
((IChannel)client).Close();
factory.Close();
//Server side
public class Service1 : IService1
{
public string GetData(int value)
{
//Read the cookies
HttpRequestMessageProperty reqProperty = (HttpRequestMessageProperty)OperationContext.Current.IncomingMessageProperties[HttpRequestMessageProperty.Name];
string cookies = reqProperty.Headers["Cookie"];
//Write a cookie
HttpResponseMessageProperty resProperty = new HttpResponseMessageProperty();
resProperty.Headers.Add("Set-Cookie", string.Format("Number={0}", value.ToString()));
OperationContext.Current.OutgoingMessageProperties.Add(HttpResponseMessageProperty.Name, resProperty);
return string.Format("You entered: {0}", value);
}
}