Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version Mismatch #44

Closed
bitaxis opened this issue Feb 18, 2015 · 7 comments
Closed

Version Mismatch #44

bitaxis opened this issue Feb 18, 2015 · 7 comments
Assignees

Comments

@bitaxis
Copy link

bitaxis commented Feb 18, 2015

Is there a way to relax or for me to override version checking behavior on the DTO assembly when de-serializing? I have a client that uses a slightly different version of the DTO than the server. They are completely compatible, but when Serialize.Linq is being invoked on the server-side, it complains about not being able to find the DTO assembly due to version number difference.

Thanks for this library. It is making my job easier and more fun.

@esskar
Copy link
Owner

esskar commented Feb 18, 2015

hi. not that i am aware of. due you have the stack trace? i will try to analyse.

@esskar esskar self-assigned this Feb 18, 2015
@bitaxis
Copy link
Author

bitaxis commented Feb 18, 2015

@esskar Here's an exemplar stack trace. The one client application is compiled, for example, with version 1.2.3.0 of the DTO assembly. The server, on the other hand is compiled with version 1.2.4.0 of the same. The DTO assembly is signed, but not sure if it makes any difference.

System.IO.FileLoadException: Could not load file or assembly 'MyDto, Version=1.2.3.0, Culture=neutral, PublicKeyToken=866519a7a698ba68' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'MyDto, Version=1.2.3.0, Culture=neutral, PublicKeyToken=866519a7a698ba68'
   at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMarkHandle stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName, ObjectHandleOnStack type)
   at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName)
   at System.Type.GetType(String typeName)
   at Serialize.Linq.ExpressionContext.<ResolveType>b__3(String n)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Serialize.Linq.ExpressionContext.ResolveType(TypeNode node)
   at MyApp.Helpers.MyExpressionContext.ResolveType(TypeNode node) in e:\nb\MyApp\Helpers\MyExpressionContext.cs:line 19
   at Serialize.Linq.Nodes.TypeNode.ToType(ExpressionContext context)
   at Serialize.Linq.Nodes.MemberNode`1.ToMemberInfo(ExpressionContext context)
   at Serialize.Linq.Nodes.MemberExpressionNode.ToExpression(ExpressionContext context)
   at Serialize.Linq.Nodes.BinaryExpressionNode.ToExpression(ExpressionContext context)
   at Serialize.Linq.Nodes.LambdaExpressionNode.ToExpression(ExpressionContext context)
   at Serialize.Linq.Nodes.ExpressionNode.ConvertToExpression[TDelegate](ExpressionNode expressionNode, ExpressionContext context)
   at Serialize.Linq.Nodes.ExpressionNode.ToExpression[TDelegate](Func`3 conversionFunction, ExpressionContext context)
   at MyApp.DataService.QueryData(QueryRequest request) in e:\nb\MyApp\DataService.svc.cs:line 76

@vsoldatkin
Copy link
Contributor

Seems like this is what @esskar exactly tried to avoid, i.e. picking wrong types with the same names. I mean how can we assure without a complex introspection that your DTO lib actually contains compatible types?

@bitaxis
Copy link
Author

bitaxis commented Feb 19, 2015

@vsoldatkin @esskar Using the sample code provided as part of Serialize.Linq for discussion, I think the answer to my question lies in how WcfContracts is versioned. That is, if I need to makes changes to WcfContracts, as long as the changes are backwards compatible, then I can maintain the same AssemblyVersion number while bumping up the AssemblyFileVersion number. That way, the WcfHost (and WcfContracts) can continue to evolve while leaving older clients behind until backwards compatibility is broken, in which case all older clients will have to upgrade.

But after studying this some more, I realized that the ultimate issue I am trying to solve is this: What if the client application had no knowledge nor access to WcfContracts, but merely consumed my WCF service using its WSDL endpoint? In that case, how can Serialize.Linq be used?

I solved it by modifying the custom expression context subclass, like so:

public override Type ResolveType(TypeNode node)
{
    var type = base.ResolveType(node);
    if (type == typeof(PersonDto))
        return typeof(Person);
    if (type == null)
    {
        // Look at node.Name and make a guess based on string matching which class
        // to map to, and ...
        return thatType;
    }
    return type;
}

I figure this is no worse than the original version, which is hard-coding a mapping based on some knowledge about the classes.

I have implemented this and it is working for me.

@esskar
Copy link
Owner

esskar commented Feb 19, 2015

@bitaxis thanks for that!

idea: when the type to serialize is from an anonymous class, we use the full qualified name, otherwise we stick to type.Fullname

how does that sound?

@bitaxis
Copy link
Author

bitaxis commented Feb 20, 2015

@esskar I think the way it is now is fine. What I ended up doing is implement two dictionaries I pre-populate. One is Dictionary<Type, Type>, which I use to look up the type to return using the non-null return value of base.ResolveType() as key. Otherwise, I use the second, which is Dictionary<Regex, Type>, and I run node.Name through all keys and taking the first match. It may not be foolproof, but a start.

Now, you could maybe clarify the purpose of ResolveType(), as I stumbled across my solution by pure happenstance.

@vsoldatkin
Copy link
Contributor

Personally I don't like the idea of FullName based type guessing in any form. I'm pretty sure I'll be able to forge a test case to break it.

I would rather stick to the safe FQN-based implementation and provide an extension point for a user to implement his own unsafe ExpressionContext (specifically his own ResolveType implementation).

What if the client application had no knowledge nor access to WcfContracts, but merely consumed my WCF service using its WSDL endpoint? In that case, how can Serialize.Linq be used?

The only safe way is to share a DTO assembly. Otherwise it falls into a broader problem: What if I want to swap actual types for another types according to some rules, taking responsibility for all the risks?

And the answer is: Then implement your own ResolveType.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants