Webservices on LLBLGen V2 and VS2005

Posts   
 
    
audiobird
User
Posts: 19
Joined: 28-Jun-2006
# Posted on: 28-Jun-2006 23:10:45   

Hi,

I've created a webservice that returns EntityCollection of customers from the Northwind DB. The code was generated using the LLBLGen V2 and adapter SQL Server specific template for the .NET 2.0. Unfortunately, the methods in my proxy class which is generated using the VS2005 return datasets. The documentation states that LLBLGen Pro v2.0 will have support code build in, so what should I do in order to generate my code correctly for having a full support of the webservices?

I was trying to enable a special, so called webservice helper task and 3 SchemaImporters tasks with registering the SchemaImporter assembly in the GAC and machine.config, but unfortunately it doesn't work.

Please advice...

Thanks

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 29-Jun-2006 00:38:35   

Did you enable the webservicehelper generator task in the preset AND the schemaimporter tasks? You also need to enable the webservicehelper generator task so you'll get the webservicehelper class in the dbspecificproject \HelperClasses namespace.

Frans Bouma | Lead developer LLBLGen Pro
audiobird
User
Posts: 19
Joined: 28-Jun-2006
# Posted on: 29-Jun-2006 11:37:08   

Hello France,

Thank you for the reply.

1) I'm using Adapter, SqlServerSpecific.NET20 template. 2) I've enabled the following tasks:

  • SD.Tasks.Adapter.Webservices.WebserviceHelperClassGenerator
  • SD.Tasks.Generic.ValidatorClassesGenerator (Otherwise it complains in the ....\DAL\DatabaseGeneric\HelperClasses\WebServiceHelper.cs)
  • SD.Tasks.Adapter.Webservices.SchemaImporter.DirectoryCreator
  • SD.Tasks.Adapter.Webservices.SchemaImporter.SchemaImporterClassGenerator
  • SD.Tasks.Adapter.Webservices.SchemaImporter.ProjectCreator 3) I've installed my SchemaImporter assembly into the GAC. 4) I've installed the SD.LLBLGen.Pro.ORMSupportClasses.NET20 assembly into the GAC.

There are 2 problems with the webservices:

1) Webmethods that return EntityCollections generated as methods that return datasets in the proxy class.

2) Calling to the method that return CustomerEntity, causes to the following fault:


See the end of this message for details on invoking 
just-in-time (JIT) debugging instead of this dialog box.

************** Exception Text **************
System.InvalidOperationException: There is an error in XML document (1, 3275). ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityFields2.ReadXml(XmlNode fieldsElement)
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityBase2.Xml2Entity(XmlNode node, Dictionary`2 processedObjectIDs, List`1 nodeEntityReferences)
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityBase2.ReadXml(XmlNode node)
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityBase2.ReadXml(XmlReader reader)
   at System.Xml.Serialization.XmlSerializationReader.ReadSerializable(IXmlSerializable serializable)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderCustomersService.Read3_GetAllCustomerResponse()
   at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer5.Deserialize(XmlSerializationReader reader)
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
   at WindowsApplication1.localhost.CustomersService.GetAllCustomer() in C:\Projects\Tests\Northwind Showcase 2\WindowsApplication1\Web References\localhost\Reference.cs:line 127
   at WindowsApplication1.Form1.button1_Click(Object sender, EventArgs e) in C:\Projects\Tests\Northwind Showcase 2\WindowsApplication1\Form1.cs:line 24
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)


************** Loaded Assemblies **************
mscorlib
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.42 (RTM.050727-4200)
    CodeBase: file:///C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/mscorlib.dll
----------------------------------------
WindowsApplication1
    Assembly Version: 1.0.0.0
    Win32 Version: 1.0.0.0
    CodeBase: file:///C:/Projects/Tests/Northwind%20Showcase%202/WindowsApplication1/bin/Debug/WindowsApplication1.exe
----------------------------------------
System.Windows.Forms
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.42 (RTM.050727-4200)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Windows.Forms/2.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
----------------------------------------
System
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.42 (RTM.050727-4200)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System/2.0.0.0__b77a5c561934e089/System.dll
----------------------------------------
System.Drawing
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.42 (RTM.050727-4200)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Drawing/2.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
----------------------------------------
System.Configuration
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.42 (RTM.050727-4200)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Configuration/2.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
----------------------------------------
System.Xml
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.42 (RTM.050727-4200)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Xml/2.0.0.0__b77a5c561934e089/System.Xml.dll
----------------------------------------
Indigo.NorthwindShowcase.DAL
    Assembly Version: 1.0.2371.19786
    Win32 Version: 1.0.2371.19786
    CodeBase: file:///C:/Projects/Tests/Northwind%20Showcase%202/WindowsApplication1/bin/Debug/Indigo.NorthwindShowcase.DAL.DLL
----------------------------------------
System.Web.Services
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.42 (RTM.050727-4200)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Web.Services/2.0.0.0__b03f5f7f11d50a3a/System.Web.Services.dll
----------------------------------------
SD.LLBLGen.Pro.ORMSupportClasses.NET20
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.0.060620
    CodeBase: file:///C:/Projects/Tests/Northwind%20Showcase%202/WindowsApplication1/bin/Debug/SD.LLBLGen.Pro.ORMSupportClasses.NET20.DLL
----------------------------------------
System.Data
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.42 (RTM.050727-4200)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_32/System.Data/2.0.0.0__b77a5c561934e089/System.Data.dll
----------------------------------------
llvajzfp
    Assembly Version: 1.0.0.0
    Win32 Version: 2.0.50727.42 (RTM.050727-4200)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System/2.0.0.0__b77a5c561934e089/System.dll
----------------------------------------
System.Design
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.42 (RTM.050727-4200)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Design/2.0.0.0__b03f5f7f11d50a3a/System.Design.dll
----------------------------------------

************** JIT Debugging **************
To enable just-in-time (JIT) debugging, the .config file for this
application or computer (machine.config) must have the
jitDebugging value set in the system.windows.forms section.
The application must also be compiled with debugging
enabled.

For example:

<configuration>
    <system.windows.forms jitDebugging="true" />
</configuration>

When JIT debugging is enabled, any unhandled exception
will be sent to the JIT debugger registered on the computer
rather than be handled by this dialog box.

Could you provide us with a sample project, demo or walkthrough of how to work with the web services and LLBLGen?

It is working if I don't use the SchemaImporter and manually modify the web service class, but it is almost impossible to work like that, not to mention the fact that VS2005 regenerates proxy class each time it is restarted.

Please advice...

Thank you

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 29-Jun-2006 12:25:45   

I'll try to reproduce it here. To be sure: - polymorphic fetches don't work over webservices. (so if your customerentity type is a supertype, forget it) - generics won't work over webservices.

I don't think you use these, but if you do, that can be a problem. The code should give you normal proxy classes, so I'll try to reproduce it and if there's an issue, will fix it.

Frans Bouma | Lead developer LLBLGen Pro
audiobird
User
Posts: 19
Joined: 28-Jun-2006
# Posted on: 29-Jun-2006 12:45:39   

Frans,

Thanks for pointing me to this: I'm using polymorfic fetches, and my entities have relational entities (Customer hold his orders, Order holds its Employee and so on...). These child entities are generated as generic EntityCollections.

Previously I was using LLBLGen for Web applications which were deployed on a single server. Now I would like to utilize new technologies like ClickOnce and build SmartClient applications that will speak with their servers using web services. I understand from you it is better not use the web services if I want to use the power of the polymorphism and generics or instead use projections and create my own entities or use remoting scenarios.

Am I understand you correctly?

Thanks

Posts: 94
Joined: 26-Feb-2006
# Posted on: 29-Jun-2006 12:47:42   

If you are at it .. and found a solution you could make again on of this nice videos ... smile

dont forget to record your voice! smile smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 29-Jun-2006 13:03:00   

audiobird wrote:

Frans,

Thanks for pointing me to this: I'm using polymorfic fetches, and my entities have relational entities (Customer hold his orders, Order holds its Employee and so on...). These child entities are generated as generic EntityCollections.

Previously I was using LLBLGen for Web applications which were deployed on a single server. Now I would like to utilize new technologies like ClickOnce and build SmartClient applications that will speak with their servers using web services. I understand from you it is better not use the web services if I want to use the power of the polymorphism and generics or instead use projections and create my own entities or use remoting scenarios.

Am I understand you correctly?

Correct simple_smile , however related entities are supported. It's just that if you have a type CustomerEntity and you return a SpecialCustomerEntity it won't work because on the client you'll get a CustomerEntity instance, not a SpecialCustomerEntity instance. This is caused by the webservice nature, so I can't solve that.

One addition: did you also alter the machine.config file? It's important you do that. Please consult the webservice templates archive in the 3rd party section on the website for documentation on that, as the docs you have don't contain the explanation in full. If you don't alter the machine.config, no schemaimporter code will be used and you will get proxies with datasets.

Adrian: hmm simple_smile . Well, recording a video using demobuilder is easy and fast. recording the voice as well, is time consuming I think. I'll think about it, but for now we'll record image-only videos wink

Frans Bouma | Lead developer LLBLGen Pro
audiobird
User
Posts: 19
Joined: 28-Jun-2006
# Posted on: 29-Jun-2006 14:27:00   

One addition: did you also alter the machine.config file? It's important you do that. Please consult the webservice templates archive in the 3rd party section on the website for documentation on that, as the docs you have don't contain the explanation in full. If you don't alter the machine.config, no schemaimporter code will be used and you will get proxies with datasets.

Yes I did. The proxy is still rendered with the damn datasets...

However, I see that using projections and custom classes is more headache than using ready and generated entity classes. I think that we'll switch to the remoting scenario.

Since my application is going to serve ~50-60 users (~10 simultaneously), I'm also thinking to deploy my application's BL, ClientServices and UI processing logic layers to the client PCs. Then UI will call to ClientServices objects which will call BL objects directly. If some day I want to deploy the BLL to a server, then I'll need to develop a ServerServices tier (using remoting) and implement ClientServices to work with the ServerServices tier remotely.

Any pros and cons?

Is there any conciderations I should take in account when using remoting and LLBLGen entities?

Thanks

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 29-Jun-2006 15:29:36   

audiobird wrote:

One addition: did you also alter the machine.config file? It's important you do that. Please consult the webservice templates archive in the 3rd party section on the website for documentation on that, as the docs you have don't contain the explanation in full. If you don't alter the machine.config, no schemaimporter code will be used and you will get proxies with datasets.

Yes I did. The proxy is still rendered with the damn datasets...

I get this too, looking into it. Must be caused by the move of the EntityCollection class from the ORMSupportClasses back to the generated code as it worked before that.

However, I see that using projections and custom classes is more headache than using ready and generated entity classes. I think that we'll switch to the remoting scenario.

Since my application is going to serve ~50-60 users (~10 simultaneously), I'm also thinking to deploy my application's BL, ClientServices and UI processing logic layers to the client PCs. Then UI will call to ClientServices objects which will call BL objects directly. If some day I want to deploy the BLL to a server, then I'll need to develop a ServerServices tier (using remoting) and implement ClientServices to work with the ServerServices tier remotely.

Any pros and cons?

Is there any conciderations I should take in account when using remoting and LLBLGen entities?

Thanks

When using remoting you should realize that the remoted service isn't a local part of your application, which thus means that if you call the remoted service to do something for you, like save entities, it's not transparent to get updated entity instances on the client, just because you've specified refetch = true.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 29-Jun-2006 15:33:58   

Indeed a bug in the schemaimporter template, it returns the type of the ORMSupportclasses.entitycollection, though that's not an existing type anymore.

(Edit) Ok, fixed it except one little detail that it keeps saying the EntityCollection is inside the ormsupportclasses dll, perhaps an old SchemaImporter in the GAC, will check. After I'm done patching I'll post the 3 updated templates here for C#.

Frans Bouma | Lead developer LLBLGen Pro
audiobird
User
Posts: 19
Joined: 28-Jun-2006
# Posted on: 29-Jun-2006 15:54:49   

Yeah, I see it now...

Thanks, Frans.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 29-Jun-2006 16:10:31   

Hurray, got it working. simple_smile Ok, I'll post the templates in a minute in a new message. The thing to keep an eye on is the assembly version of the schemaimporter dll. If you're going to re-generate it, you should give it a new version number, and re-register it in the gac, but also you should adjust the machine.config again, as the version changed!

have to check the typedlists as well, these don't look ok to me too, so I'll check them out also, then fix the templates, then post them here. Stay tuned.

Frans Bouma | Lead developer LLBLGen Pro
audiobird
User
Posts: 19
Joined: 28-Jun-2006
# Posted on: 29-Jun-2006 16:37:30   

Hurray, got it working. Ok, I'll post the templates in a minute in a new message.

Good news...! simple_smile Thanks for the quick response and fix.

The thing to keep an eye on is the assembly version of the schemaimporter dll. If you're going to re-generate it, you should give it a new version number, and re-register it in the gac, but also you should adjust the machine.config again, as the version changed!

I think it is not necessary, since I can also remove the schemaimporter assembly from the GAC and install it again. Why should I keep the old version of the schemaimporter?

When using remoting you should realize that the remoted service isn't a local part of your application, which thus means that if you call the remoted service to do something for you, like save entities, it's not transparent to get updated entity instances on the client, just because you've specified refetch = true.

However, I can do the following:


//In the UI layer:
entity=myservice.SaveEntity(entity);


//in the remoted (MarshalByRefObject) Service layer on the server:
return manager.Save(entity); //return the saved and refetched entity to the client


//In the BL layer on the server:
adapter.SaveEntity(entity, true, true); // for the recursive save and refetching after the save
return entity; //return the saved and refetched entity to the client

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 29-Jun-2006 16:51:33   

Ok, updated SchemaImporter template:

C#


///////////////////////////////////////////////////////////////
// This is generated code. 
//////////////////////////////////////////////////////////////
// Code is generated using LLBLGen Pro version: <[LLBLGenVersion]>
// Code is generated on: <[Time]>
// Code is generated using templates: <[TemplateName]>
// Templates vendor: Solutions Design.
// Templates version: <[TemplateVersion]>
//////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Xml.Serialization.Advanced;

namespace <[RootNamespace]>.SchemaImporter
{
    /// <summary>
    /// Generic schema importer for wsdl support so a webservice build with this generated code will result in a stub class with properly typed parameters instead of 'DataSet'.
    /// </summary>
    public class EntityClassesSchemaImporter : SchemaImporterExtension
    {
        /// <summary>
        /// Allows you to manipulate the code generated by examining the imported schema and specifying the CLR type that it maps to.
        /// </summary>
        /// <param name="type">An <see cref="T:System.Xml.Schema.XmlSchemaType"></see> that represents the XSD type.</param>
        /// <param name="context">An <see cref="T:System.Xml.Schema.XmlSchemaObject"></see> that represents schema information, such as the line number of the XML element.</param>
        /// <param name="schemas">An <see cref="T:System.Xml.Serialization.XmlSchemas"></see> that contains the collection of schemas in the document.</param>
        /// <param name="importer">The <see cref="T:System.Xml.Serialization.XmlSchemaImporter"></see> that is the importer being used.</param>
        /// <param name="compileUnit">A <see cref="T:System.CodeDom.CodeCompileUnit"></see> to which you can add CodeDOM structures to generate alternative code for the XSD.</param>
        /// <param name="mainNamespace">A <see cref="T:System.CodeDom.CodeNamespace"></see> that represents the current namespace for the element.</param>
        /// <param name="options">A <see cref="T:System.Xml.Serialization.CodeGenerationOptions"></see> for the setting options on the code compiler.</param>
        /// <param name="codeProvider">A <see cref="T:System.CodeDom.Compiler.CodeDomProvider"></see> that is used to generate the new code.</param>
        /// <returns>
        /// The name of the CLR type that this maps to.
        /// </returns>
        public override string ImportSchemaType(XmlSchemaType type, XmlSchemaObject context, XmlSchemas schemas, XmlSchemaImporter importer, 
                CodeCompileUnit compileUnit, CodeNamespace mainNamespace, CodeGenerationOptions options, CodeDomProvider codeProvider)
        {
            return null;
        }


        /// <summary>
        /// Allows you to manipulate the code generated by examining the imported schema and specifying the CLR type that it maps to.
        /// </summary>
        /// <param name="name">The name of the element.</param>
        /// <param name="ns">The namespace of the element.</param>
        /// <param name="context">An <see cref="T:System.Xml.Schema.XmlSchemaObject"></see> that represents schema information, such as the line number of the XML element.</param>
        /// <param name="schemas">An <see cref="T:System.Xml.Serialization.XmlSchemas"></see> that contains the collection of schemas in the document.</param>
        /// <param name="importer">The <see cref="T:System.Xml.Serialization.XmlSchemaImporter"></see> that is the importer being used.</param>
        /// <param name="compileUnit">A <see cref="T:System.CodeDom.CodeCompileUnit"></see> to which you can add CodeDOM structures to generate alternative code for the XSD.</param>
        /// <param name="mainNamespace">A <see cref="T:System.CodeDom.CodeNamespace"></see> that represents the current namespace for the element.</param>
        /// <param name="options">A <see cref="T:System.Xml.Serialization.CodeGenerationOptions"></see> for the setting options on the code compiler.</param>
        /// <param name="codeProvider">A <see cref="T:System.CodeDom.Compiler.CodeDomProvider"></see> that is used to generate the new code.</param>
        /// <returns>
        /// The name of the CLR type that this maps to.
        /// </returns>
        public override string ImportSchemaType(string name, string ns, XmlSchemaObject context, XmlSchemas schemas, XmlSchemaImporter importer, 
            CodeCompileUnit compileUnit, CodeNamespace mainNamespace, CodeGenerationOptions options, CodeDomProvider codeProvider)
        {
            if (ns.Equals("http://<[RootNamespace]>/xml/serialization"))
            {
                switch (name)
                {
                    #region Entity Classes              
<[Foreach Entity]>
                    case "<[CurrentEntityName]>Entity":
                        compileUnit.ReferencedAssemblies.Add("<[RootNamespace]>.dll");
                        mainNamespace.Imports.Add(new CodeNamespaceImport("<[RootNamespace]>.EntityClasses"));
                        return "<[RootNamespace]>.EntityClasses.<[CurrentEntityName]>Entity";
                    <[NextForeach]>
                    #endregion
                    
                    #region EntityCollection
                    case "EntityCollection":
                        compileUnit.ReferencedAssemblies.Add("<[RootNamespace]>.dll");
                        mainNamespace.Imports.Add(new CodeNamespaceImport("<[RootNamespace]>.HelperClasses"));
                        return "<[RootNamespace]>.HelperClasses.EntityCollection";
                    #endregion
                    
                    #region TypedLists
<[Foreach TypedList]>
                    case "<[CurrentTypedListName]>TypedList":
                        compileUnit.ReferencedAssemblies.Add("<[RootNamespace]>.dll");
                        mainNamespace.Imports.Add(new CodeNamespaceImport("<[RootNamespace]>.TypedListClasses"));
                        return "<[RootNamespace]>.TypedListClasses.<[CurrentTypedListName]>TypedList";
                    <[NextForeach]>
                    #endregion

                    #region TypedViews
<[Foreach TypedView]>
                    case "<[CurrentTypedViewName]>TypedView":
                        compileUnit.ReferencedAssemblies.Add("<[RootNamespace]>.dll");
                        mainNamespace.Imports.Add(new CodeNamespaceImport("<[RootNamespace]>.TypedViewClasses"));
                        return "<[RootNamespace]>.TypedViewClasses.<[CurrentTypedViewName]>TypedView";
                    <[NextForeach]>
                    #endregion
                }
            }
            return null;
        }
    }
}

VB.NET:


' ///////////////////////////////////////////////////////////////
' This is generated code. 
' //////////////////////////////////////////////////////////////
' Code is generated Imports LLBLGen Pro version: <[LLBLGenVersion]>
' Code is generated on: <[Time]>
' Code is generated Imports templates: <[TemplateName]>
' Templates vendor: Solutions Design.
' Templates version: <[TemplateVersion]>
' //////////////////////////////////////////////////////////////
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Xml.Schema
Imports System.Xml.Serialization
Imports System.CodeDom
Imports System.CodeDom.Compiler
Imports System.Xml.Serialization.Advanced

Namespace <[RootNamespace]>.SchemaImporter

    ''' <summary>
    ''' Generic schema importer for wsdl support so a webservice build with this generated code will result in a stub class with properly typed parameters instead of 'DataSet'.
    ''' </summary>
    Public Class EntityClassesSchemaImporter 
        Inherits SchemaImporterExtension
    
        ''' <summary>
        ''' Allows you to manipulate the code generated by examining the imported schema and specifying the CLR type that it maps to.
        ''' </summary>
        ''' <param name="type">An <see cref="T:System.Xml.Schema.XmlSchemaType"></see> that represents the XSD type.</param>
        ''' <param name="context">An <see cref="T:System.Xml.Schema.XmlSchemaObject"></see> that represents schema information, such as the line number of the XML element.</param>
        ''' <param name="schemas">An <see cref="T:System.Xml.Serialization.XmlSchemas"></see> that contains the collection of schemas in the document.</param>
        ''' <param name="importer">The <see cref="T:System.Xml.Serialization.XmlSchemaImporter"></see> that is the importer being used.</param>
        ''' <param name="compileUnit">A <see cref="T:System.CodeDom.CodeCompileUnit"></see> to which you can add CodeDOM structures to generate alternative code for the XSD.</param>
        ''' <param name="mainNamespace">A <see cref="T:System.CodeDom.CodeNamespace"></see> that represents the current namespace for the element.</param>
        ''' <param name="options">A <see cref="T:System.Xml.Serialization.CodeGenerationOptions"></see> for the setting options on the code compiler.</param>
        ''' <param name="codeProvider">A <see cref="T:System.CodeDom.Compiler.CodeDomProvider"></see> that is used to generate the new code.</param>
        ''' <returns>
        ''' The name of the CLR type that this maps to.
        ''' </returns>
        Public Overrides Function ImportSchemaType ( type As XmlSchemaType, context As XmlSchemaObject, schemas As XmlSchemas, importer As XmlSchemaImporter, compileUnit As CodeCompileUnit, mainNamespace As CodeNamespace, options As CodeGenerationOptions, codeProvider As CodeDomProvider) As String
            Return Nothing
        End Function


        ''' <summary>
        ''' Allows you to manipulate the code generated by examining the imported schema and specifying the CLR type that it maps to.
        ''' </summary>
        ''' <param name="name">The name of the element.</param>
        ''' <param name="ns">The namespace of the element.</param>
        ''' <param name="context">An <see cref="T:System.Xml.Schema.XmlSchemaObject"></see> that represents schema information, such as the line number of the XML element.</param>
        ''' <param name="schemas">An <see cref="T:System.Xml.Serialization.XmlSchemas"></see> that contains the collection of schemas in the document.</param>
        ''' <param name="importer">The <see cref="T:System.Xml.Serialization.XmlSchemaImporter"></see> that is the importer being used.</param>
        ''' <param name="compileUnit">A <see cref="T:System.CodeDom.CodeCompileUnit"></see> to which you can add CodeDOM structures to generate alternative code for the XSD.</param>
        ''' <param name="mainNamespace">A <see cref="T:System.CodeDom.CodeNamespace"></see> that represents the current namespace for the element.</param>
        ''' <param name="options">A <see cref="T:System.Xml.Serialization.CodeGenerationOptions"></see> for the setting options on the code compiler.</param>
        ''' <param name="codeProvider">A <see cref="T:System.CodeDom.Compiler.CodeDomProvider"></see> that is used to generate the new code.</param>
        ''' <returns>
        ''' The name of the CLR type that this maps to.
        ''' </returns>
        Public Overrides Function ImportSchemaType ( name As String, schemaNamespace As String, context As XmlSchemaObject, schemas As XmlSchemas, importer As XmlSchemaImporter, compileUnit As CodeCompileUnit, mainNamespace As CodeNamespace, options As CodeGenerationOptions, codeProvider As CodeDomProvider) As String
            If ns.Equals("http://<[RootNamespace]>/xml/serialization") Then
                Select Case name
<[Foreach Entity]>
                    Case "<[CurrentEntityName]>Entity"
                        compileUnit.ReferencedAssemblies.Add("<[RootNamespace]>.dll")
                        mainNamespace.Imports.Add(new CodeNamespaceImport("<[RootNamespace]>.EntityClasses"))
                        Return "<[RootNamespace]>.EntityClasses.<[CurrentEntityName]>Entity"
                    <[NextForeach]>

                    Case "EntityCollection"
                        compileUnit.ReferencedAssemblies.Add("<[RootNamespace]>.dll")
                        mainNamespace.Imports.Add(New CodeNamespaceImport("<[RootNamespace]>.HelperClasses"))
                        Return "<[RootNamespace]>.HelperClasses.EntityCollection"

<[Foreach TypedList]>
                    Case "<[CurrentTypedListName]>TypedList"
                        compileUnit.ReferencedAssemblies.Add("<[RootNamespace]>.dll")
                        mainNamespace.Imports.Add(New CodeNamespaceImport("<[RootNamespace]>.TypedListClasses"))
                        Return "<[RootNamespace]>.TypedListClasses.<[CurrentTypedListName]>TypedList"
                    <[NextForeach]>

<[Foreach TypedView]>
                    Case "<[CurrentTypedViewName]>TypedView"
                        compileUnit.ReferencedAssemblies.Add("<[RootNamespace]>.dll")
                        mainNamespace.Imports.Add(New CodeNamespaceImport("<[RootNamespace]>.TypedViewClasses"))
                        Return "<[RootNamespace]>.TypedViewClasses.<[CurrentTypedViewName]>TypedView"
                    <[NextForeach]>
                End Select
            End If
            Return Nothing
        End Function
    End Class
End Namespace

Webservice helper: C#


///////////////////////////////////////////////////////////////
// This is generated code. 
//////////////////////////////////////////////////////////////
// Code is generated using LLBLGen Pro version: <[LLBLGenVersion]>
// Code is generated on: <[Time]>
// Code is generated using templates: <[TemplateName]>
// Templates vendor: Solutions Design.
// Templates version: <[TemplateVersion]>
//////////////////////////////////////////////////////////////
using System;
using System.Xml.Serialization;
using System.Xml.Schema;
using System.Xml;
using System.IO;

using <[RootNamespace]>;
using <[RootNamespace]>.HelperClasses;
using <[RootNamespace]>.FactoryClasses;
using <[RootNamespace]>.RelationClasses;

using SD.LLBLGen.Pro.ORMSupportClasses;

#region Entity Classes
namespace <[RootNamespace]>.EntityClasses
{
<[Foreach Entity]>
    [XmlSchemaProvider("GetEntitySchema")]
    public partial class <[CurrentEntityName]>Entity
    {
        /// <summary>
        /// Method which provides a schema for IXmlSerializable implementation so no proxies are generated.
        /// </summary>
        /// <param name="schemaSet">schema set which is the current schema for the type to produce</param>
        /// <returns></returns>
        public <[If IsSubType]>new<[EndIf]> static XmlQualifiedName GetEntitySchema(XmlSchemaSet schemaSet)
        {
            string namespaceToUse = "http://<[RootNamespace]>/xml/serialization";
            XmlSchema xs = XmlSchema.Read(
                new StringReader(
                    string.Format("<xs:schema id='<[CurrentEntityName]>EntitySchema' targetNamespace='{0}' elementFormDefault='qualified' xmlns='{0}' xmlns:mstns='{0}' xmlns:xs='http://www.w3.org/2001/XMLSchema'><xs:complexType name='<[CurrentEntityName]>Entity'><xs:sequence><xs:any minOccurs='0'/></xs:sequence></xs:complexType></xs:schema>",
                        namespaceToUse)), null);
            schemaSet.XmlResolver = new XmlUrlResolver();
            schemaSet.Add(xs);
            return new XmlQualifiedName("<[CurrentEntityName]>Entity", namespaceToUse);
        }
        
    }
<[NextForeach]>
}
#endregion

#region EntityCollection
namespace <[RootNamespace]>.HelperClasses
{
    [XmlSchemaProvider("GetEntityCollectionSchema")]
    public partial class EntityCollection
    {
        /// <summary>
        /// Method which provides a schema for IXmlSerializable implementation so no proxies are generated.
        /// </summary>
        /// <param name="schemaSet">schema set which is the current schema for the type to produce</param>
        /// <returns></returns>
        public static XmlQualifiedName GetEntityCollectionSchema(XmlSchemaSet schemaSet)
        {
            string namespaceToUse = "http://<[RootNamespace]>/xml/serialization";
            XmlSchema xs = XmlSchema.Read(
                new StringReader(
                    string.Format("<xs:schema id='EntityCollectionSchema' targetNamespace='{0}' elementFormDefault='qualified' xmlns='{0}' xmlns:mstns='{0}' xmlns:xs='http://www.w3.org/2001/XMLSchema'><xs:complexType name='EntityCollection'></xs:complexType></xs:schema>",
                        namespaceToUse)), null);
            schemaSet.XmlResolver = new XmlUrlResolver();
            schemaSet.Add(xs);
            return new XmlQualifiedName("EntityCollection", namespaceToUse);
        }
    }
}
#endregion

#region TypedView Classes
namespace <[RootNamespace]>.TypedViewClasses
{
<[Foreach TypedView CrLf]>
    [XmlSchemaProvider("GetTypedViewSchema")]
    public partial class <[CurrentTypedViewName]>TypedView
    {
        /// <summary>
        /// Method which provides a schema for IXmlSerializable implementation so no proxies are generated.
        /// </summary>
        /// <param name="schemaSet">schema set which is the current schema for the type to produce</param>
        /// <returns></returns>
        public static XmlQualifiedName GetTypedViewSchema(XmlSchemaSet schemaSet)
        {
            string namespaceToUse = "http://<[RootNamespace]>/xml/serialization";
            XmlSchema xs = XmlSchema.Read(
                new StringReader(
                    string.Format("<xs:schema id='<[CurrentTypedViewName]>TypedViewSchema' targetNamespace='{0}' elementFormDefault='qualified' xmlns='{0}' xmlns:mstns='{0}' xmlns:xs='http://www.w3.org/2001/XMLSchema'><xs:complexType name='<[CurrentTypedViewName]>TypedView'><xs:sequence><xs:any minOccurs='0'/></xs:sequence></xs:complexType></xs:schema>",
                        namespaceToUse)), null);
            schemaSet.XmlResolver = new XmlUrlResolver();
            schemaSet.Add(xs);
            return new XmlQualifiedName("<[CurrentTypedListName]>TypedList", namespaceToUse);
        }

        protected override System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }
    }<[NextForeach]>
}
#endregion


#region TypedList Classes
namespace <[RootNamespace]>.TypedListClasses
{
<[Foreach TypedList CrLf]>
    [XmlSchemaProvider("GetTypedListSchema")]
    public partial class <[CurrentTypedListName]>TypedList
    {
        /// <summary>
        /// Method which provides a schema for IXmlSerializable implementation so no proxies are generated.
        /// </summary>
        /// <param name="schemaSet">schema set which is the current schema for the type to produce</param>
        /// <returns></returns>
        public static XmlQualifiedName GetTypedListSchema(XmlSchemaSet schemaSet)
        {
            string namespaceToUse = "http://<[RootNamespace]>/xml/serialization";
            XmlSchema xs = XmlSchema.Read(
                new StringReader(
                    string.Format("<xs:schema id='<[CurrentTypedListName]>TypedListSchema' targetNamespace='{0}' elementFormDefault='qualified' xmlns='{0}' xmlns:mstns='{0}' xmlns:xs='http://www.w3.org/2001/XMLSchema'><xs:complexType name='<[CurrentTypedListName]>TypedList'><xs:sequence><xs:any minOccurs='0'/></xs:sequence></xs:complexType></xs:schema>",
                        namespaceToUse)), null);
            schemaSet.XmlResolver = new XmlUrlResolver();
            schemaSet.Add(xs);
            return new XmlQualifiedName("<[CurrentTypedListName]>TypedList", namespaceToUse);
        }

        protected override System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }
    }<[NextForeach]>
}
#endregion

VB.NET


' ///////////////////////////////////////////////////////////////
' This is generated code. 
' //////////////////////////////////////////////////////////////
' Code is generated Imports LLBLGen Pro version: <[LLBLGenVersion]>
' Code is generated on: <[Time]>
' Code is generated Imports templates: <[TemplateName]>
' Templates vendor: Solutions Design.
' Templates version: <[TemplateVersion]>
' //////////////////////////////////////////////////////////////
Imports System
Imports System.Xml.Serialization
Imports System.Xml.Schema
Imports System.Xml
Imports System.IO

Imports <[RootNamespace]>
Imports <[RootNamespace]>.HelperClasses
Imports <[RootNamespace]>.FactoryClasses
Imports <[RootNamespace]>.RelationClasses

Imports SD.LLBLGen.Pro.ORMSupportClasses

#Region "Entity Classes"

Namespace <[RootNamespace]>.EntityClasses
<[Foreach Entity]>
    <XmlSchemaProvider("GetEntitySchema")> _
    Public Partial Class <[CurrentEntityName]>Entity
        ''' <summary>
        ''' Method which provides a schema for IXmlSerializable implementation so no proxies are generated.
        ''' </summary>
        ''' <param name="schemaSet">schema set which is the current schema for the type to produce</param>
        ''' <returns></returns>
        Public <[If IsSubType]>Shadows<[EndIf]> Shared Function GetEntitySchema(schemaSet As XmlSchemaSet ) As XmlQualifiedName
            Dim namespaceToUse As String = "http://<[RootNamespace]>/xml/serialization"
            xs As XmlSchema = XmlSchema.Read( _
                New StringReader( _
                    String.Format("<xs:schema id='<[CurrentEntityName]>EntitySchema' targetNamespace='{0}' elementFormDefault='qualified' xmlns='{0}' xmlns:mstns='{0}' xmlns:xs='http://www.w3.org/2001/XMLSchema'><xs:complexType name='<[CurrentEntityName]>Entity'><xs:sequence><xs:any minOccurs='0'/></xs:sequence></xs:complexType></xs:schema>", _
                        namespaceToUse)), Nothing)
            schemaSet.XmlResolver = New XmlUrlResolver()
            schemaSet.Add(xs)
            Return New XmlQualifiedName("<[CurrentEntityName]>Entity", namespaceToUse)
        End Function
    End Class
<[NextForeach]>
End Namespace
#End Region

#Region "EntityCollection"
Namespace <[RootNamespace]>.HelperClasses
    <XmlSchemaProvider("GetEntityCollectionSchema")> _
    Public Partial Class EntityCollection
        Public Shared Function GetEntityCollectionSchema(schemaSet As XmlSchemaSet ) As XmlQualifiedName 
            Dim namespaceToUse As String = "http://<[RootNamespace]>/xml/serialization"
            xs As XmlSchema = XmlSchema.Read( _
                New StringReader( _
                    String.Format("<xs:schema id='EntityCollectionSchema' targetNamespace='{0}' elementFormDefault='qualified' xmlns='{0}' xmlns:mstns='{0}' xmlns:xs='http://www.w3.org/2001/XMLSchema'><xs:complexType name='EntityCollection'></xs:complexType></xs:schema>", _
                        namespaceToUse)), Nothing)
            schemaSet.XmlResolver = New XmlUrlResolver()
            schemaSet.Add(xs)
            Return New XmlQualifiedName("EntityCollection", namespaceToUse)
        End Function
    End Class
End Namespace
#End Region

#Region "TypedView Classes"
Namespace <[RootNamespace]>.TypedViewClasses
<[Foreach TypedView CrLf]>
    <XmlSchemaProvider("GetTypedViewSchema")> _
    Public Partial Class <[CurrentTypedViewName]>TypedView 

        ''' <summary>
        ''' Method which provides a schema for IXmlSerializable implementation so no proxies are generated.
        ''' </summary>
        ''' <param name="schemaSet">schema set which is the current schema for the type to produce</param>
        ''' <returns></returns>
        Public Shared Function GetTypedViewSchema(schemaSet As XmlSchemaSet) As XmlQualifiedName 
            Dim namespaceToUse As String = "http://<[RootNamespace]>/xml/serialization"
            xs As XmlSchema = XmlSchema.Read( _
                New StringReader( _
                    string.Format("<xs:schema id='<[CurrentTypedViewName]>TypedViewSchema' targetNamespace='{0}' elementFormDefault='qualified' xmlns='{0}' xmlns:mstns='{0}' xmlns:xs='http://www.w3.org/2001/XMLSchema'><xs:complexType name='<[CurrentTypedViewName]>TypedView'><xs:sequence><xs:any minOccurs='0'/></xs:sequence></xs:complexType></xs:schema>", _
                        namespaceToUse)), Nothing)
            schemaSet.XmlResolver = New XmlUrlResolver()
            schemaSet.Add(xs)
            Return New XmlQualifiedName("<[CurrentTypedListName]>TypedList", namespaceToUse)
        End Function

        Protected Overrides Function GetSchema() As System.Xml.Schema.XmlSchema 
            Return Nothing
        End Function
    End Class<[NextForeach]>
End Namespace
#End Region

#Region "TypedList Classes"
Namespace <[RootNamespace]>.TypedListClasses
<[Foreach TypedList CrLf]>
    <XmlSchemaProvider("GetTypedListSchema")> _
    Public Partial Class <[CurrentTypedListName]>TypedList 

        ''' <summary>
        ''' Method which provides a schema for IXmlSerializable implementation so no proxies are generated.
        ''' </summary>
        ''' <param name="schemaSet">schema set which is the current schema for the type to produce</param>
        ''' <returns></returns>
        Public Shared Function GetTypedListSchema(schemaSet As XmlSchemaSet) As XmlQualifiedName 
            Dim namespaceToUse As String = "http://<[RootNamespace]>/xml/serialization"
            xs As XmlSchema = XmlSchema.Read( _
                New StringReader( _
                    string.Format("<xs:schema id='<[CurrentTypedListName]>TypedListSchema' targetNamespace='{0}' elementFormDefault='qualified' xmlns='{0}' xmlns:mstns='{0}' xmlns:xs='http://www.w3.org/2001/XMLSchema'><xs:complexType name='<[CurrentTypedListName]>TypedList'><xs:sequence><xs:any minOccurs='0'/></xs:sequence></xs:complexType></xs:schema>", _
                        namespaceToUse)), Nothing)
            schemaSet.XmlResolver = New XmlUrlResolver()
            schemaSet.Add(xs)
            Return New XmlQualifiedName("<[CurrentTypedListName]>TypedList", namespaceToUse)
        End Function

        Protected Overrides Function GetSchema() As System.Xml.Schema.XmlSchema 
            Return Nothing
        End Function
    End Class<[NextForeach]>
End Namespace
#End Region

@ your example code: yes that's the way simple_smile Just as long as you don't re-use entity instances on the client, you're ok simple_smile

Frans Bouma | Lead developer LLBLGen Pro
audiobird
User
Posts: 19
Joined: 28-Jun-2006
# Posted on: 29-Jun-2006 17:35:17   

Thanks for the fixed templates, Franssimple_smile

@ your example code: yes that's the way Just as long as you don't re-use entity instances on the client, you're ok

What if I reuse the entities on the client? Each time I do a save of the entity should I manually update the reused entity's object state on the client? Can you suggest me any pattern to work with in this case?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 29-Jun-2006 20:33:58   

audiobird wrote:

Thanks for the fixed templates, Franssimple_smile

@ your example code: yes that's the way Just as long as you don't re-use entity instances on the client, you're ok

What if I reuse the entities on the client? Each time I do a save of the entity should I manually update the reused entity's object state on the client? Can you suggest me any pattern to work with in this case?

You could use: myCustomer.Fields = fetchedEntityFromService.Fields;

to update an instance's fields object simple_smile

Frans Bouma | Lead developer LLBLGen Pro
audiobird
User
Posts: 19
Joined: 28-Jun-2006
# Posted on: 29-Jun-2006 20:40:09   

Thanks simple_smile