WCF Linq to SQL Table - System.Data.Linq.Table cannot be serialized - linq

I can't figure this out as I go through demos that seem to work. I have a WCF service I was trying to use Linq to SQL with. However, all I ever get is the error System.Data.Linq.Table cannot be serialized. So I started with my own class thinking I could build it back up until get the error. Problem is I get the error even trying to use an empty class. Just using the "As System.Linq.Table(Of xxx)" on my method gives me this error.
Type 'System.Data.Linq.Table`1[LinqADMRequest2b]' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. See the Microsoft .NET Framework documentation for other supported types.
Imports System.ServiceModel
Imports System.ServiceModel.Activation
Imports System.Runtime.Serialization
Imports System.Collections.Generic
Imports Linq
<ServiceContract(Namespace:="")> _
<ServiceBehavior(IncludeExceptionDetailInFaults:=True)> _
<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)> _
Public Class ComplyTrackWCFService
_
Public Function GetTestRequests() As System.Data.Linq.Table(Of LinqADMRequest2b)
'Dim ct As New Linq2.ComplyTrackDataContext()
'Dim queryresults = ct.ADMRequests 'ct.ADMRequestGetListByUser("", "155")
'Return queryresults
End Function
End Class
<DataContract()> _
<Serializable()> _
Public Class LinqADMRequest2b
Implements ISerializable
Private _firstName As String
_
Public Property FirstName() As String
Get
Return _firstName
End Get
Set(ByVal Value As String)
_firstName = Value
End Set
End Property
Public Sub GetObjectData(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext) Implements System.Runtime.Serialization.ISerializable.GetObjectData
End Sub
End Class
As you can see the GetTestRequests() doesn't do anything other then say it's going to return a System.Data.Linq.Table(Of LinqADMRequest2b)
I can't get the LinqADMRequest2b to serialize.
Type 'System.Data.Linq.Table`1[LinqADMRequest2b]' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. See the Microsoft .NET Framework documentation for other supported types.

Don't return Table<T> from your service. It's a complex queryable type that depends on its DataContext and isn't an in-memory collection.
Do return List<T>, you can convert the Table<T> to a List<T> by calling System.Linq.Enumerable.ToList().

Try putting
<DataMember> attribute on your properties of you own class.
Also, it's better to create lightweight DataContract object to pass down the line rather than big bulky dude like the linq table.

Related

MongoDB - override default Serializer for a C# primitive type

I'd like to change the representation of C# Doubles to rounded Int64 with a four decimal place shift in the serialization C# Driver's stack for MongoDB. In other words, store (Double)29.99 as (Int64)299900
I'd like this to be transparent to my app. I've had a look at custom serializers but I don't want to override everything and then switch on the Type with fallback to the default, as that's a bit messy.
I can see that RegisterSerializer() won't let me add one for an existing type, and that BsonDefaultSerializationProvider has a static list of primitive serializers and it's marked as internal with private members so I can't easily subclass.
I can also see that it's possible to RepresentAs Int64 for Doubles, but this is a cast not a conversion. I need essentially a cast AND a conversion in both serialization directions.
I wish I could just give the default serializer a custom serializer to override one of it's own, but that would mean a dirty hack.
Am I missing a really easy way?
You can definitely do this, you just have to get the timing right. When the driver starts up there are no serializers registered. When it needs a serializer, it looks it up in the dictionary where it keeps track of the serializers it knows about (i.e. the ones that have been registered). Only it it can't find one in the dictionary does it start figuring out where to get one (including calling the serialization providers) and if it finds one it registers it.
The limitation in RegisterSerializer is there so that you can't replace an existing serializer that has already been used. But that doesn't mean you can't register your own if you do it early enough.
However, keep in mind that registering a serializer is a global operation, so if you register a custom serializer for double it will be used for all doubles, which could lead to unexpected results!
Anyway, you could write the custom serializer something like this:
public class CustomDoubleSerializer : BsonBaseSerializer
{
public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options)
{
var rep = bsonReader.ReadInt64();
return rep / 100.0;
}
public override void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
{
var rep = (long)((double)value * 100);
bsonWriter.WriteInt64(rep);
}
}
And register it like this:
BsonSerializer.RegisterSerializer(typeof(double), new CustomDoubleSerializer());
You could test it using the following class:
public class C
{
public int Id;
public double X;
}
and this code:
BsonSerializer.RegisterSerializer(typeof(double), new CustomDoubleSerializer());
var c = new C { Id = 1, X = 29.99 };
var json = c.ToJson();
Console.WriteLine(json);
var r = BsonSerializer.Deserialize<C>(json);
Console.WriteLine(r.X);
You can also use your own serialization provider to tell Mongo which serializer to use for certain types, which I ended up doing to mitigate some of the timing issues mentioned when trying to override existing serializers. Here's an example of a serialisation provider that overrides how to serialize decimals:
public class CustomSerializationProvider : IBsonSerializationProvider
{
public IBsonSerializer GetSerializer(Type type)
{
if (type == typeof(decimal)) return new DecimalSerializer(BsonType.Decimal128);
return null; // falls back to Mongo defaults
}
}
If you return null from your custom serialization provider, it will fall back to using Mongo's default serialization provider.
Once you've written your provider, you just need to register it:
BsonSerializer.RegisterSerializationProvider(new CustomSerializationProvider());
I looked through the latest iteration of the driver's code and checked if there's some sort of backdoor to set custom serializers. I am afraid there's none; you should open an issue in the project's bug tracker if you think this needs to be looked at for future iterations of the driver (https://jira.mongodb.org/).
Personally, I'd open a ticket -- and if a quick workaround is necessary or required, I'd subclass DoubleSerializer, implement the new behavior, and then use Reflection to inject it into either MongoDB.Bson.Serialization.Serializers.DoubleSerializer.__instance or MongoDB.Bson.Serialization.BsonDefaultSerializationProvider.__serializers.

How to send a List<object> to a Web Method?

I am developing a web application using MVC 3 and ASMX Web Services.
I am trying to send a List< object > to a Web Method, but I get the following error:
" cannot convert from 'System.Collections.Generic.List' to 'WebServiceClass.ArrayOfAnyType' "
This is my Web Service definition:
public class WebServiceClass : System.Web.Services.WebService
{
[WebMethod]
public bool MyWebMethod(List<object> ParameterValues)
{
//do stuff..
}
}
And this is the block of code where I call the Web Method:
List<object> ParameterValues = new List<object>();
WebServiceClass.WebServiceClassSoapClient MyWebService = new WebServiceClass.WebServiceClassSoapClient();
//I use actual objects here, this is just for an example
ParameterValues.Add(new DateTime(2012,5,2));
ParameterValues.Add(23);
ParameterValues.Add("some string");
MyWebService.MyWebMethod(ParameterValues);
My idea was to save time and pass Lists of objects to all Web Methods instead of defining WebMethod(DateTime date, int someint, string somestring).
Is there a solution for this?
Best regards.
If your method expects 3 parameters of type DateTime, int, and string than define a method with this arguments. Otherwise you will have to case down and your solution is not type-safe.
Are all your methods in code taking a list of objects as a parameter? Probably not. And the same should apply to web methods.

what do these "let" and "get' mean?

here is some documentation generated from activeX, can you explain me what do those "let" and "get" mean?
Public Property Get ReadyState() ' property ReadyState
Public Property Get TotalFrames() ' property TotalFrames
Public Property Get Playing() ' property Playing
Public Propety Let Playing() ' property Playing
Public Property Get Quality() ' property Quality
Public Propety Let Quality() ' property Quality
Public Property Get ScaleMode() ' property ScaleMode
Public Propety Let ScaleMode() ' property ScaleMode
Public Property Get AlignMode() ' property AlignMode
Public Propety Let AlignMode() ' property AlignMode
I am a Java developer, I need to embed a activex control in my java gui application
Indeed, these correspond to "getters" and "setters". However, the syntax looks wrong. I suppose that the type could be Variant (which would probably not have a corresponding type for Java), but in that case, I would expect the Property Let code to be:
Public Property Let MyValue(ByVal value)
End Property
Normally, you should include the type:
Public Property Let MyValue(ByVal value As Integer)
End Property
Public Property Get MyValue As Integer
End Property
I would go back to the tool which gave you this nonsense VB and see if you get better information. Alternatively, you need something which will allow you to read the type library of the OCX control. If you don't have Visual Basic, you will be able to use VBA in Word, Excel, Access etc.

Is there any way to clean up the following generic method using any of the new C# 4 features?

I've just modified a method for handling my DDD commands (previously it had no return type):
public static CommandResult<TReturn> Execute<TCommand, TReturn>(TCommand command)
where TCommand : IDomainCommand
{
var handler = IoCFactory.GetInstance<ICommandHandler<TCommand, TReturn>>();
return handler.Handle(command);
}
The method is fine, and does what I want it to do, however using it creates some fugly code:
CommandResult<Customer> result =
DomainCommands.Execute<CustomerCreateCommand, Customer>
(
new CustomerCreateCommand(message)
);
Before I added the Customer return type TReturn, it was nice and tidy and the method could infer the types from its usage. However that's no longer possible.
Is there any way using any new C# features that I could rewrite the above to make it tidier, i.e. using Func, Action, Expression, etc? I'm probably expecting the impossible, but I'm getting fed up of writing so much code to just call a single method that used to be very simple.
One option to reduce it slightly is to have a static generic type for the type parameter that can't be inferred, allowing you to have a generic method with just one type parameter that can be inferred:
public static class DomainCommands<TReturn>
{
public static CommandResult<TReturn> Execute<TCommand>(TCommand command)
where TCommand : IDomainCommand
{
var handler = IoCFactory.GetInstance<ICommandHandler<TCommand, TReturn>>();
return handler.Handle(command);
}
}
Then:
var result = DomainCommands<Customer>.Execute(new CustomerCreateCommand(msg));
It's not much nicer, but it's slightly better. Of course, if the domain command type itself could be generic, that might help - so CustomerCreateCommand would implement IDomainCommand<Customer> for example. If you still needed a nongeneric IDomainCommand, you could make IDomainCommand<T> derive from IDomainCommand.

Why is FxCop raising the error "Types that own disposable fields should be disposable" on a class with no disposable fields?

I have a LINQ object with an additional method added to it. The class has no disposable properties or methods, but FxCop is raising the error "Types that own disposable fields should be disposable" and referencing that class.
I've reduced the code this far and still receive the error:
partial class WikiPage
{
public PagePermissionSet GetUserPermissions(Guid? userId) {
using (WikiTomeDataContext context = new WikiTomeDataContext()) {
var permissions =
from wiki in context.Wikis
from pageTag in context.VirtualWikiPageTags
select new {};
return null;
}
}
}
However, if I remove EITHER of the from clauses, FxCop stops giving the error:
partial class WikiPage
{
public PagePermissionSet GetUserPermissions(Guid? userId) {
using (WikiTomeDataContext context = new WikiTomeDataContext()) {
var permissions =
from pageTag in context.VirtualWikiPageTags
select new {};
return null;
}
}
}
Or
partial class WikiPage
{
public PagePermissionSet GetUserPermissions(Guid? userId) {
using (WikiTomeDataContext context = new WikiTomeDataContext()) {
var permissions =
from wiki in context.Wikis
select new {};
return null;
}
}
}
PagePermissionSet is not disposable.
Is this a false positive? Or is the LINQ code somehow generating a disposable field on the class? If it isn't a false positive, FxCop is recommending that I implement the IDisposable interface, but what would I do in the Dispose method?
EDIT:
The full FxCop error is:
"Implement IDisposable on 'WikiPage' because it
creates members of the following IDisposable types:
'WikiTomeDataContext'. If 'WikiPage' has previously
shipped, adding new members that implement IDisposable
to this type is considered a breaking change to existing
consumers."
Edit 2:
This is the disassembled code that raises the error:
public PagePermissionSet GetUserPermissions(Guid? userId)
{
using (WikiTomeDataContext context = new WikiTomeDataContext())
{
ParameterExpression CS$0$0001;
ParameterExpression CS$0$0003;
var permissions = context.Wikis.SelectMany(Expression.Lambda<Func<Wiki, IEnumerable<VirtualWikiPageTag>>>(Expression.Property(Expression.Constant(context), (MethodInfo) methodof(WikiTomeDataContext.get_VirtualWikiPageTags)), new ParameterExpression[] { CS$0$0001 = Expression.Parameter(typeof(Wiki), "wiki") }), Expression.Lambda(Expression.New((ConstructorInfo) methodof(<>f__AnonymousType8..ctor), new Expression[0], new MethodInfo[0]), new ParameterExpression[] { CS$0$0001 = Expression.Parameter(typeof(Wiki), "wiki"), CS$0$0003 = Expression.Parameter(typeof(VirtualWikiPageTag), "pageTag") }));
return null;
}
}
Edit 3:
There does appear to be a closure class containing a reference to the DataContext. Here is its disassembled code:
[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
// Fields
public WikiTomeDataContext context;
// Methods
public <>c__DisplayClass1();
}
My guess is that the two From clauses generate a call to SelectMany with a closure on your data context. The instance of the closure has a field to the datacontext which is causes the FxCop warning. This is nothing to worry about.
There's only one instance of your datacontext, which you clean up via the using block. Because the closure doesn't have a finalizer there's no performance or saftey implication here in the FxCop warning.
I noticed that this is a partial class. Have you checked the other implementation file for the class and see if it has an IDisposable member that is not being disposed?
I don't think the generated closure is at fault here. Closures are generated with certain attributes that should cause FxCop to ignore warnings like this.
EDIT
Further investigation by the OP showed this to be an issue with an IDisposable field being lifted into a closure.
Unfortunately there isn't a whole lot you can do about this. There is no way to make the closure implement IDisposable. Event if you could there is no way to call IDisposable on the closure instance.
The best way to approach this problem is to rewrite your code in such a way that a disposable value does not get captured in the closure. Disposable fields should always be disposed when they are finished and capturing it in a closure prevents you from doing this.
If you're returning a LINQ query from your method, consumers will iterate over the results using foreach.
When a consumer finishes a foreach loop, it internally calls dispose on the IEnumerable source (in this case, your LINQ query). This will dispose the WikiTomeDataContext.
However, if a consumer made a call to method returning a LINQ query but never iterated over the results, it would appear that enumerable would never be disposed (that is, until the garbage collector cleaned up the object). This would lead to your WikiTomeDataContext not being disposed until garbage collection.
One way you might be able to get around this problem is by calling .ToArray on the result of your LINQ query, call dispose on your context, then return the array.
Your code that gives the error uses WikiDataContext.
Your two examples that do not give an error use WikiTomeDataContext.
Maybe there is some difference between these two that is causing the error.

Resources