Possible bug with SqlServer 2005 calling UDT Read method?

Hi,

I have a UDT written in C# that is formatted with UserDefined. I added the IBinarySerialize interface and it was implemented automatically by Visual Studio as follows:



void IBinarySerialize.Read(System.IO.BinaryReader r)
void IBinarySerialize.Write(System.IO.BinaryWriter w)

 


This compiles fine, and the assembly deploys fine. However, when I execute a call to a stored procedure and pass a UDT that has these methods implemented, I get a message saying:

System.Data.SqlClient.SqlException: Could not find method 'Read' for type 'Test.Seller' in assembly 'TestUDT'

So it appears that the deserialization code isn't looking for the IBinarySerialize interface, just a Read method that takes a BinaryWriter. (Oops!)

If I change the name of the functions to:



public void Read(System.IO.BinaryReader r)
public void Write(System.IO.BinaryWriter w)

 


Everything works fine.

SqlServer 2005 should look for either the IBinarySerialize interface and/or the Read/Write methods. If not then add documentation to warn people not to define the functions this way.

I'd prefer that the IBinarySerialize interface was supported so that someone using this class on the app side has to explicitly cast an instance to IBinarySerialize to access these methods, rather than just having them available as public methods.

Is this a bug, or intentional If intentional, why

Thanks
]Monty[



Answer this question

Possible bug with SqlServer 2005 calling UDT Read method?

  • Lev Semenets - MSFT

    SQL Server does check for the interface, if you have Format set to UserDefined.  The issue is that in C#, class members default to private access.  Your explicit interface implementation did not include an access designator -- so the methods were private and SQL Server did not call them. 
     

    --
    Adam Machanic
    Pro SQL Server 2005, available now
    http://www..apress.com/book/bookDisplay.html bID=457
    --
     
     

    Hi,

    I have a UDT written in C# that is formatted with UserDefined. I added the IBinarySerialize interface and it was implemented automatically by Visual Studio as follows:

    [code language="c#"]
    void IBinarySerialize.Read(System.IO.BinaryReader r)
    void IBinarySerialize.Write(System.IO.BinaryWriter w)
    [/code]

    This compiles fine, and the assembly deploys fine. However, when I execute a call to a stored procedure and pass a UDT that has these methods implemented, I get a message saying:

    System.Data.SqlClient.SqlException: Could not find method 'Read' for type 'Test.Seller' in assembly 'TestUDT'

    So it appears that the deserialization code isn't looking for the IBinarySerialize interface, just a Read method that takes a BinaryWriter. (Oops!)

    If I change the name of the functions to:

    [code language="c#"]
    public void Read(System.IO.BinaryReader r)
    public void Write(System.IO.BinaryWriter w)
    [/code]

    Everything works fine.

    SqlServer 2005 should look for either the IBinarySerialize interface and/or the Read/Write methods. If not then add documentation to warn people not to define the functions this way.

    I'd prefer that the IBinarySerialize interface was supported so that someone using this class on the app side has to explicitly cast an instance to IBinarySerialize to access these methods, rather than just having them available as public methods.

    Is this a bug, or intentional If intentional, why

    Thanks
    ]Monty[


  • A. Dachauer

    Monty - Ah, I see what you are saying now. Interesting point, worth investigating why explicit interface implementation is not supported.

    Niels

  • WeeZarD

    Monty - what exactly are you trying to do here The Read and Write methods are not supposed to be used directly from the client. As Steven says (and Adam alludes to) the Read and Write methods are ment to be used by SQL Server internally.

    It'd be interesting to se your code - both the UDT code as well as the client side code.

    Niels

  • cnewbie

    Hi Monty,

    Adam was right when he said that the interface methods weren't public and you can check this by looking at the generated IL.  Although the interface is public, to access the methods in an explicit interface implementation one would need to go through the interface. SQL Server needs to access the UDT read and write methods directly so using explicit interfaces won't work.

    See the MSDN documentation http://msdn.microsoft.com/library/default.asp url=/library/en-us/csspec/html/vclrfcsharpspec_13_4_1.asp for more information.

    Steven



  • ExCon

    Hi Adam,

    Well the only problem with your reply is that they are public. It is a public interface. And I can't put a public on the functions when using the interface name type form. Compiler won't let you.

    Next :)

    ]Monty[

  • KayJay

    Hi guys,

    Here's the problem: In Visual Studio and all the docs, if I use UserDefined format, it says I have to implement the IBinarySerialize interface. My point is that this is not exactly correct, because if you implement the interface and mark the methods as interface methods, it does not work. The correct answer is that you need to implement a public Read method that takes a BinaryReader and a public Write method that takes a BinaryWriter, which coincidentally implements the IBinarySerialize interface, but don't code the methods as interface methods. IBinarySerialize COULD be directly supported, but SqlServer 2005 does not look for the interface.

    As far as access to the Read and Write functions, the fact that I don't want any code other than the framework to call them is exactly my point. By not using the interface, SqlServer is forcing me to expose the Read and Write methods as public methods which could be called. If the interface method format were used, at least you'd have to cast the instance to an IBinarySerialize to call them,

    Again my question is not whether the above is correct, but why does it work this way Is this intentional I'm trying to find out if there is something subtle I'm missing, or is this just an oversight on the part of the documentation and/or SqlServer UDT implementation.

    Also after re-reading the doc linked to above I think the following quote may clarify some of what I'm trying to say: (Highlighted in red)

    Explicit interface member implementations have different accessibility characteristics than other members. Because explicit interface member implementations are never accessible through their fully qualified name in a method invocation or a property access, they are in a sense private. However, since they can be accessed through an interface instance, they are in a sense also public.

    Explicit interface member implementations serve two primary purposes:

    • Because explicit interface member implementations are not accessible through class or struct instances, they allow interface implementations to be excluded from the public interface of a class or struct. This is particularly useful when a class or struct implements an internal interface that is of no interest to a consumer of that class or struct.
    • Explicit interface member implementations allow disambiguation of interface members with the same signature. Without explicit interface member implementations it would be impossible for a class or struct to have different implementations of interface members with the same signature and return type, as would it be impossible for a class or struct to have any implementation at all of interface members with the same signature but with different return types.


    ]Monty[

  • David Dilworth

    • Because explicit interface member implementations are not accessible through class or struct instances, they allow interface implementations to be excluded from the public interface of a class or struct. This is particularly useful when a class or struct implements an internal interface that is of no interest to a consumer of that class or struct.



    So basically explicit interface methods are not supported, it is not a bug, and the documentation that doesn't mention this is alright. And I also assume that there is no subtle nuance I'm missing.

    ]Monty[


  • Joe Zott


    Here's the problem: In Visual Studio and all the docs, if I use UserDefined format, it says I have to implement the IBinarySerialize interface. My point is that this is not exactly correct, because if you implement the interface and mark the methods as interface methods, it does not work. The correct answer is that you need to implement a public Read method that takes a BinaryReader and a public Write method that takes a BinaryWriter, which coincidentally implements the IBinarySerialize interface, but don't code the methods as interface methods. IBinarySerialize COULD be directly supported, but SqlServer 2005 does not look for the interface.
     
        SQL Server does look for the interface.  Have you tried creating a type with Format set to UserDefined that doesn't implement the interface, but does include public Read and Write methods with the same signature   It does not work.  You will receive the following exception:  'Type "your_assembly.your_type" is marked for user-defined serialization, but does not implement the "System.Data.Microsoft.SqlServer.Server.IBinarySerialize" interface.'
     
        There is no coincidencidental implementation of the interface possible.  You either implement it or you don't.  Whether you do so implicitly or explicitly is another matter entirely.  Why the concern with explicit implementation
     

    --
    Adam Machanic
    Pro SQL Server 2005, available now
    http://www..apress.com/book/bookDisplay.html bID=457
    --
     

  • Possible bug with SqlServer 2005 calling UDT Read method?