Despite of the heading, the blog contains links for the very different parts of programming knowledge. CLR and .NET via C#, SQL and a lot of technologies, wich comes along with .NET.
вторник, 13 марта 2012 г.
пятница, 24 февраля 2012 г.
.NET. Version compatibility issue walkaround
Issue:
Application uses Library.dll from the same solution and UI.dll from external solution.
Problem is, that UI.dll wants Library.dll too.
With this scheme I faced the issue, when application refused to work with messages about assambly versions.
The first walkaround was to use bindingRedirect element in the configuration. But this solution doesn't woek if you are changing Library.dll and it's version as well.
I stayed with next solution. I turned off assembly signing locally for the UI.dll. If .NET assembly is not signed, it doesn't matter which version you used to build dll. You can use UI.dll with eny higher version of Library.dll.
Application uses Library.dll from the same solution and UI.dll from external solution.
Problem is, that UI.dll wants Library.dll too.
With this scheme I faced the issue, when application refused to work with messages about assambly versions.
The first walkaround was to use bindingRedirect element in the configuration. But this solution doesn't woek if you are changing Library.dll and it's version as well.
I stayed with next solution. I turned off assembly signing locally for the UI.dll. If .NET assembly is not signed, it doesn't matter which version you used to build dll. You can use UI.dll with eny higher version of Library.dll.
четверг, 16 февраля 2012 г.
пятница, 10 февраля 2012 г.
.NET + Fiddler
If you want to have Fiddler like net statistics in your .NET application you can download FiddlerCore library.
http://www.fiddler2.com/fiddler/Core/
Integration with any .NET application can give simply fantastic results:
-- 22 GET http://dashboard.re.tfn.com/ccnetda200 text/xml
-- ServerConnected: 2/10/2012 5:44:45 PM
-- ClientDoneResponse: 2/10/2012 5:44:46 PM
http://www.fiddler2.com/fiddler/Core/
Integration with any .NET application can give simply fantastic results:
-- 22 GET http://dashboard.re.tfn.com/ccnetda200 text/xml
-- ServerConnected: 2/10/2012 5:44:45 PM
-- ClientDoneResponse: 2/10/2012 5:44:46 PM
среда, 5 октября 2011 г.
Custom serialization in WCF
Here is short description and set of links about custom serialization in WCF.
http://msdn.microsoft.com/en-us/magazine/cc163302.aspx
http://sharpserializer.codeplex.com/
http://wcfpro.wordpress.com/2011/03/03/idispatchmessageformatter/
http://wcfpro.wordpress.com
http://www.codeproject.com/KB/WCF/extension-wcf-behavior.aspx?display=Print
The problem was following. We are not satisfied with DataContractSerializer performance and would like to use own custom serializar.
For the first glance, this seems strangem because DataContractSerializer is main feature of WCF services. It's very fast and easy to use. It's true.
But when you need to send quite big collection of large objects from client to server, you meet the problem of large size of messages.
Reason of it, that result of data contract serializer is xml. And node names are equal to names of properties.
Besides that, null values present in the xml.
It's not very efficient.
Standard BinaryMessage encoding has practically the same message size. You can see object property names in the output.
Solution - using of custom serializer.
The only issue that there is not much information about this.
Solution is following.
According to the msdn article Extending WCF with Custom Behaviors, the only place for custom serializer is dispatcher. MSDN offers to implement own IDispatchMessageFormatter. It will deserialize requests from clients and serialize responces.
The same on the client - IClientMessageFormatter.
Here is what I have implemented for my case:
I used SharpSerializer.
As you can see, I still use DataContractSerializer here. The aim is to create prototype WCF Message. With all headers. I just don't know how to implement it myself.
Next step is to apply this for your WCF service. As wcfpro.wordpress advices, I have implemented IOperationBehavior interface. But with some small changes.
This will allow you to turn you serializer on with following way:
Have you noticed CustomOperationBehavior attribute?
It's practically everything. No one change in the DataContracts.
The last thing is client tuning.
This is really all. Custom serializer will work. And you'll see in the Fiddler different message, not xml.
Of course you can use any serializer you like. The tricky part is implementing of formetters.
You should be sure, that serializer works correctly.
You should control all process of creation WCF message, control headers, Action property and so on. This is the infinite source of erros.
And with custom serializer you may not receive FaultExceptions. So you should control messages using some web debugger. For example, Fiddler.
Restrictions of the current solution - client and server should have shared library with data contracts. But this restriction refers to the current serializer.
http://msdn.microsoft.com/en-us/magazine/cc163302.aspx
http://sharpserializer.codeplex.com/
http://wcfpro.wordpress.com/2011/03/03/idispatchmessageformatter/
http://wcfpro.wordpress.com
http://www.codeproject.com/KB/WCF/extension-wcf-behavior.aspx?display=Print
The problem was following. We are not satisfied with DataContractSerializer performance and would like to use own custom serializar.
For the first glance, this seems strangem because DataContractSerializer is main feature of WCF services. It's very fast and easy to use. It's true.
But when you need to send quite big collection of large objects from client to server, you meet the problem of large size of messages.
Reason of it, that result of data contract serializer is xml. And node names are equal to names of properties.
Besides that, null values present in the xml.
It's not very efficient.
Standard BinaryMessage encoding has practically the same message size. You can see object property names in the output.
Solution - using of custom serializer.
The only issue that there is not much information about this.
Solution is following.
According to the msdn article Extending WCF with Custom Behaviors, the only place for custom serializer is dispatcher. MSDN offers to implement own IDispatchMessageFormatter. It will deserialize requests from clients and serialize responces.
The same on the client - IClientMessageFormatter.
Here is what I have implemented for my case:
Custom message formatter
- using System;
- using System.IO;
- using System.Xml;
- using System.ServiceModel.Dispatcher;
- using System.ServiceModel.Channels;
- using System.IO.Compression;
- namespace SharedLibrary
- {
- public class CustomMessageFormatter : IDispatchMessageFormatter, IClientMessageFormatter
- {
- IClientMessageFormatter InnerClientFormatter;
- IDispatchMessageFormatter InnerDispatchFormatter;
- private const string ROOT = "MessageData";
- public CustomMessageFormatter(IClientMessageFormatter innerClientFormatter)
- {
- InnerClientFormatter = innerClientFormatter;
- }
- public CustomMessageFormatter(IDispatchMessageFormatter innerDispatchFormatter)
- {
- InnerDispatchFormatter = innerDispatchFormatter;
- }
- #region Stream Compression
- private Stream CompressStream(Stream inStream)
- {
- var outStream = new MemoryStream();
- CompressStream(inStream, outStream);
- outStream.Position = 0;
- return outStream;
- }
- /// <summary>
- /// Compress 'inStream' and write all data into 'outStream'
- /// </summary>
- private void CompressStream(Stream inStream, Stream outStream)
- {
- using (var gzipStream = new GZipStream(outStream, CompressionMode.Compress, true))
- {
- gzipStream.Flush();
- inStream.CopyTo(gzipStream);
- }
- }
- /// <summary>
- /// Get decompression stream. Not dispose 'inStream' while not end work with stream.
- /// </summary>
- private Stream DecompressStream(Stream inStream, bool leaveOpenInStream = false)
- {
- return new GZipStream(inStream, CompressionMode.Decompress, leaveOpenInStream);
- }
- #endregion
- #region IDispatchMessageFormatter
- public void DeserializeRequest(System.ServiceModel.Channels.Message message, object[] parameters)
- {
- Polenter.Serialization.SharpSerializer serializer = new Polenter.Serialization.SharpSerializer(true);
- using (var inStream = GetBodyInnerContentStream(message))
- {
- for (int i = 0; i < parameters.Length; i++)
- {
- parameters[i] = serializer.Deserialize(inStream);
- }
- }
- }
- public System.ServiceModel.Channels.Message SerializeReply(System.ServiceModel.Channels.MessageVersion messageVersion, object[] parameters, object result)
- {
- Polenter.Serialization.SharpSerializer serializer = new Polenter.Serialization.SharpSerializer(true);
- //stream will be closed in the ContentStreamProvider
- MemoryStream outStream = new MemoryStream();
- serializer.Serialize(result, outStream);
- outStream.Position = 0;
- return Message.CreateMessage(messageVersion, null, new ContentStreamProvider(CompressStream(outStream), ROOT));
- }
- #endregion
- /// <summary>
- /// Create a new message bases on other one and with body writer stream.
- /// </summary>
- /// <param name="prototype"></param>
- /// <param name="sourceStream">Stream of body content</param>
- /// <param name="tagName"></param>
- private static Message CreateMessage(Message prototype, Stream contentStream, string tagName = null)
- {
- Message msg = Message.CreateMessage(prototype.Version, null, new ContentStreamProvider(contentStream, tagName));
- msg.Headers.CopyHeadersFrom(prototype);
- msg.Properties.CopyProperties(prototype.Properties);
- return msg;
- }
- #region IClientMessageFormatter
- public object DeserializeReply(Message message, object[] parameters)
- {
- Polenter.Serialization.SharpSerializer serializer = new Polenter.Serialization.SharpSerializer(true);
- using (var inStream = GetBodyInnerContentStream(message))
- {
- return serializer.Deserialize(DecompressStream(inStream, true));
- }
- }
- public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
- {
- Polenter.Serialization.SharpSerializer serializer = new Polenter.Serialization.SharpSerializer(true);
- //stream will be closed in the ContentStreamProvider
- MemoryStream outStream = new MemoryStream();
- foreach (var parameter in parameters)
- {
- serializer.Serialize(parameter, outStream);
- }
- //check
- outStream.Position = 0;
- Message prototype = null;
- if (InnerClientFormatter != null)
- {
- prototype = InnerClientFormatter.SerializeRequest(messageVersion, parameters);
- messageVersion = prototype.Version;
- }
- return CreateMessage(prototype, outStream, ROOT);
- }
- #endregion
- /// <summary>
- /// Gets stream of inner element content of the message body.
- /// </summary>
- private Stream GetBodyInnerContentStream(Message message)
- {
- using (var bodyStream = new MemoryStream())
- {
- using (XmlDictionaryWriter bodyWriter = XmlDictionaryWriter.CreateBinaryWriter(bodyStream))
- {
- message.WriteBodyContents(bodyWriter);
- bodyWriter.Flush();
- bodyStream.Position = 0;
- using (var bodyReader = XmlDictionaryReader.CreateBinaryReader(bodyStream, XmlDictionaryReaderQuotas.Max))
- {
- bodyReader.MoveToStartElement();
- var contentStream = new MemoryStream(bodyReader.ReadElementContentAsBase64());
- contentStream.Position = 0;
- return contentStream;
- }
- }
- }
- }
- }
- }
Content stream provider code
- using System;
- using System.IO;
- using System.Xml;
- using System.ServiceModel.Channels;
- namespace SharedLibrary
- {
- internal sealed class ContentStreamProvider : BodyWriter, IStreamProvider
- {
- private readonly Stream _innerStream;
- private readonly string _tagName;
- public ContentStreamProvider(Stream stream, string tagName = null)
- : base(false)
- {
- _innerStream = stream;
- _tagName = tagName;
- }
- protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
- {
- if (!string.IsNullOrEmpty(_tagName))
- {
- writer.WriteStartElement(_tagName);
- }
- writer.WriteValue((IStreamProvider)this);
- if (!string.IsNullOrEmpty(_tagName))
- {
- writer.WriteEndElement();
- }
- }
- Stream IStreamProvider.GetStream()
- {
- return _innerStream;
- }
- void IStreamProvider.ReleaseStream(Stream stream)
- {
- if (stream != null)
- {
- stream.Dispose();
- }
- }
- }
- }
I used SharpSerializer.
As you can see, I still use DataContractSerializer here. The aim is to create prototype WCF Message. With all headers. I just don't know how to implement it myself.
Next step is to apply this for your WCF service. As wcfpro.wordpress advices, I have implemented IOperationBehavior interface. But with some small changes.
CustomOperationBehavior
- using System;
- using System.ServiceModel.Description;
- using System.ServiceModel.Dispatcher;
- namespace SharedLibrary
- {
- public class CustomOperationBehavior : Attribute, IOperationBehavior
- {
- public CustomOperationBehavior()
- {
- }
- IOperationBehavior innerFormatterBehavior;
- internal IOperationBehavior InnerFormatterBehavior
- {
- get { return innerFormatterBehavior; }
- set { innerFormatterBehavior = value; }
- }
- #region IOperationBehavior Members
- public void AddBindingParameters(OperationDescription description, System.ServiceModel.Channels.BindingParameterCollection parameters)
- {
- if (innerFormatterBehavior != null)
- {
- innerFormatterBehavior.AddBindingParameters(description, parameters);
- }
- }
- public void ApplyClientBehavior(OperationDescription description, ClientOperation runtime)
- {
- if (innerFormatterBehavior != null && runtime.Formatter == null)
- {
- // no formatter has been applied yet
- innerFormatterBehavior.ApplyClientBehavior(description, runtime);
- }
- runtime.Formatter = new CustomMessageFormatter(runtime.Formatter);
- }
- public void ApplyDispatchBehavior(OperationDescription description, DispatchOperation runtime)
- {
- if (innerFormatterBehavior != null && runtime.Formatter == null)
- {
- // no formatter has been applied yet
- innerFormatterBehavior.ApplyDispatchBehavior(description, runtime);
- }
- runtime.Formatter = new CustomMessageFormatter(runtime.Formatter);
- }
- public void Validate(OperationDescription description)
- {
- if (innerFormatterBehavior != null)
- {
- innerFormatterBehavior.Validate(description);
- }
- }
- #endregion
- }
- }
This will allow you to turn you serializer on with following way:
Code Snippet
- using System;
- using System.ServiceModel;
- using System.Runtime.Serialization;
- using SharedLibrary;
- namespace Test.ProxyServer
- {
- [ServiceContract]
- public interface IService
- {
- [OperationContract]
- string GetData(int value);
- [OperationContract]
- [CustomOperationBehavior]
- CompositeType[] GetDataUsingDataContract(CompositeType composite);
- }
- }
Have you noticed CustomOperationBehavior attribute?
It's practically everything. No one change in the DataContracts.
The last thing is client tuning.
Client settings:
- using (ServiceReference.ServiceClient client = new ServiceReference.ServiceClient())
- {
- // Apply query string formatter
- foreach (OperationDescription operationDescription in client.Endpoint.Contract.Operations)
- {
- operationDescription.Behaviors.Add(new CustomOperationBehavior() as IOperationBehavior);
- }
- var deals = client.GetDataUsingDataContract(new CompositeType() { BoolValue = true, DecimalValue = 5, StringValue1 = "1", StringValue2 = "2", StringValue3 = "3" });
- }
This is really all. Custom serializer will work. And you'll see in the Fiddler different message, not xml.
Of course you can use any serializer you like. The tricky part is implementing of formetters.
You should be sure, that serializer works correctly.
You should control all process of creation WCF message, control headers, Action property and so on. This is the infinite source of erros.
And with custom serializer you may not receive FaultExceptions. So you should control messages using some web debugger. For example, Fiddler.
Restrictions of the current solution - client and server should have shared library with data contracts. But this restriction refers to the current serializer.
понедельник, 26 сентября 2011 г.
Fiddler for localhost
Here is the very simple tip how to use fiddler for local queries.
Intead of http://localhost:1234/MyApp/...
After that fiddler will catch such requests:
Hope it will help.
понедельник, 4 июля 2011 г.
Текстовый поиск
Линка на статью с хабра, посвященная текстовому поиску http://habrahabr.ru/blogs/algorithm/123320/#habracut
Подписаться на:
Сообщения (Atom)
