- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
WCF vs netTcpBinding vs EntityCollection<>
Joined: 05-Mar-2008
Hi,
Could somebody explain my why my generic collection i.e. EntityCollection<UserEntity> could not be passed from client to server as a parameter of method? I am using WCF with binary binding netTcp. When I want to pass generic collection over the wire I get following exception:
Server stack trace:
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameter(XmlDictionaryWriter writer, PartInfo part, Object graph)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameters(XmlDictionaryWriter writer, PartInfo[] parts, Object[] parameters)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.SerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, Object[] parameters, Object returnValue, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer)
at System.ServiceModel.Channels.BodyWriter.WriteBodyContents(XmlDictionaryWriter writer)
at System.ServiceModel.Channels.Message.OnWriteMessage(XmlDictionaryWriter writer)
at System.ServiceModel.Channels.BufferedMessageWriter.WriteMessage(Message message, BufferManager bufferManager, Int32 initialOffset, Int32 maxSizeQuota)
at System.ServiceModel.Channels.BinaryMessageEncoderFactory.BinaryMessageEncoder.WriteMessage(Message message, Int32 maxMessageSize, BufferManager bufferManager, Int32 messageOffset)
at System.ServiceModel.Channels.FramingDuplexSessionChannel.EncodeMessage(Message message)
at System.ServiceModel.Channels.FramingDuplexSessionChannel.OnSend(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.OutputChannel.Send(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.DuplexChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at AbacaSystems.AbacaNET.WCF.ServiceInterface.IService.FetchEntityCollection(IToken token, IEntityCollection2 collection)
at AbacaSystems.AbacaNET.UI.MainWindow.sliderApplicationRotate_ValueChanged(Object sender, RoutedPropertyChangedEventArgs`1 e) in D:\fp\Abaca\AbacaNET\src\UI\AbacaSystems.AbacaNET.UI\Windows\MainWindow.xaml.cs:line 94
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.Controls.Slider.OnValueChanged(Double oldValue, Double newValue)
at System.Windows.Controls.Primitives.RangeBase.OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, OperationType operationType)
at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, OperationType operationType, Boolean isInternal)
at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
at System.Windows.Controls.Slider.MoveToNextTick(Double direction)
at System.Windows.Input.CommandBinding.OnExecuted(Object sender, ExecutedRoutedEventArgs e)
at System.Windows.Input.CommandManager.ExecuteCommandBinding(Object sender, ExecutedRoutedEventArgs e, CommandBinding commandBinding)
at System.Windows.Input.CommandManager.FindCommandBinding(CommandBindingCollection commandBindings, Object sender, RoutedEventArgs e, ICommand command, Boolean execute)
at System.Windows.Input.CommandManager.FindCommandBinding(Object sender, RoutedEventArgs e, ICommand command, Boolean execute)
at System.Windows.Input.CommandManager.OnExecuted(Object sender, ExecutedRoutedEventArgs e)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
at System.Windows.Input.RoutedCommand.ExecuteImpl(Object parameter, IInputElement target, Boolean userInitiated)
at MS.Internal.Commands.CommandHelpers.CriticalExecuteCommandSource(ICommandSource commandSource, Boolean userInitiated)
at System.Windows.Controls.Primitives.RepeatButton.OnClick()
at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonDown(MouseButtonEventArgs e)
at System.Windows.Controls.Primitives.RepeatButton.OnMouseLeftButtonDown(MouseButtonEventArgs e)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
at System.Windows.UIElement.OnMouseDownThunk(Object sender, MouseButtonEventArgs e)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
at System.Windows.Input.InputManager.ProcessStagingArea()
at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.TranslateAndDispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Application.RunInternal(Window window)
at AbacaSystems.AbacaNET.UI.App.Main() in D:\fp\Abaca\AbacaNET\src\UI\AbacaSystems.AbacaNET.UI\obj\Debug\App.g.cs:line 0
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
I know that generics can not be used in wcf when wsHttpBinding is set (becuse of xml serialization). But I thought that when I change binding to netTcpBinding, binary seraliazation will be used and everything will be fine. Now I see that there is an error each time when I want to use generic entity collection.
What should be done to use entityCollection<userEntity> as a parameter for WCF with netTcpBinding?
Cheers
WCF can't deal with generics. Maybe this link could be helpful: http://llblgen.com/TinyForum/Messages.aspx?ThreadID=15500&StartAtMessage=0𕇑
Joined: 05-Mar-2008
I think I fave found the solution how to use generic entity collections in wcf. All you have to do is to repleace DataContractSerializerBehavior to NetDataContractSerializerBehavior.
To do this, add following classes to your project:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Description;
namespace blabla
{
/// <summary>
///
/// </summary>
public class NetDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
#region Constructors
public NetDataContractSerializerOperationBehavior(OperationDescription operationDescription) : base(operationDescription) { }
#endregion
#region Overrides
public override System.Runtime.Serialization.XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return new System.Runtime.Serialization.NetDataContractSerializer();
}
public override System.Runtime.Serialization.XmlObjectSerializer CreateSerializer(Type type, System.Xml.XmlDictionaryString name, System.Xml.XmlDictionaryString ns, IList<Type> knownTypes)
{
return new System.Runtime.Serialization.NetDataContractSerializer();
}
#endregion
#region Helpers
internal static void ReplaceDataContractSerializer(ContractDescription contractDescription)
{
foreach (OperationDescription operationDescription in contractDescription.Operations)
ReplaceDataContractSerializer(operationDescription);
}
internal static void ReplaceDataContractSerializer(OperationDescription operationDescription)
{
DataContractSerializerOperationBehavior behavior = operationDescription.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (behavior != null)
{
//operationDescription.Behaviors.Remove(behavior);
//operationDescription.Behaviors.Add(new NetDataContractSerializerOperationBehavior(operationDescription));
int idx = operationDescription.Behaviors.IndexOf(behavior);
operationDescription.Behaviors.Remove(behavior);
operationDescription.Behaviors.Insert(idx, new NetDataContractSerializerOperationBehavior(operationDescription));
}
}
#endregion
}
/// <summary>
///
/// </summary>
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class)]
public class NetDataContractFormatAttribute : Attribute, System.ServiceModel.Description.IContractBehavior
{
#region Implementation - System.ServiceModel.Description.IContractBehavior
void IContractBehavior.ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
NetDataContractSerializerOperationBehavior.ReplaceDataContractSerializer(endpoint.Contract);
}
void IContractBehavior.ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)
{
NetDataContractSerializerOperationBehavior.ReplaceDataContractSerializer(endpoint.Contract);
}
void IContractBehavior.AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { }
void IContractBehavior.Validate(ContractDescription contractDescription, ServiceEndpoint endpoint) { }
#endregion
}
/// <summary>
///
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class NetDataContractOperationFormatAttribute : Attribute, System.ServiceModel.Description.IOperationBehavior
{
#region Implementation - System.ServiceModel.Description.IOperationBehavior
public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
{
NetDataContractSerializerOperationBehavior.ReplaceDataContractSerializer(description);
}
public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
{
NetDataContractSerializerOperationBehavior.ReplaceDataContractSerializer(description);
}
public void AddBindingParameters(OperationDescription description, System.ServiceModel.Channels.BindingParameterCollection parameters) { }
public void Validate(OperationDescription description) { }
#endregion
}
}
Add this attribute [NetDataContractFormatAttribute] for the ServiceInterface. And have fun with generic entity collections. Thanks this you may even pass RelationPredicateBucket or PrefetchPath over the wire. You don't need to add extra attributes like ServiceKnownType for each generic entity collection. This solution works for wsHttp and netTcp binding type.
There is only one restriction.
The NetDataContractSerializer differs from the DataContractSerializer in one important way: the NetDataContractSerializer includes CLR type information in the serialized XML, whereas the DataContractSerializer does not. Therefore, the NetDataContractSerializer can be used only if both the serializing and deserializing ends share the same CLR types.
If you are using NetDataContractSerializer, service and all clients must be written in .NET framework.
cheers, Dawid
It is necessary only for the outside collection, so the extra type info inside the XML should also be small, as the rest of the XML is produced by the entities themselves.
Thanks for the info!