EntityCollections and WebServices

Posts   
 
    
swallace
User
Posts: 648
Joined: 18-Aug-2003
# Posted on: 13-Oct-2003 07:39:39   

I'm attempting to create a webservice that returns an EntityCollection. The function is simple, thus:

    <WebMethod()> _
    Public Function getFreeStuff(ByVal m_churchid As Integer) As ChumFreeStuffCollection

        Dim m_result As ChumFreeStuffCollection
        Dim m_church As New ChumChurchesEntity(m_churchid)

        m_result = m_church.GetMultiChumFreeStuff(True)

        getFreeStuff = m_result

    End Function

but the function barfs this error message:

Cannot serialize member SD.LLBLGen.Pro.ORMSupportClasses.EntityBase.Validator of type SD.LLBLGen.Pro.ORMSupportClasses.IValidator because it is an interface. 
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.NotSupportedException: Cannot serialize member SD.LLBLGen.Pro.ORMSupportClasses.EntityBase.Validator of type SD.LLBLGen.Pro.ORMSupportClasses.IValidator because it is an interface.

Source Error: 

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.  

Stack Trace: 


[NotSupportedException: Cannot serialize member SD.LLBLGen.Pro.ORMSupportClasses.EntityBase.Validator of type SD.LLBLGen.Pro.ORMSupportClasses.IValidator because it is an interface.]
   System.Xml.Serialization.TypeScope.ImportTypeDesc(Type type, Boolean canBePrimitive, MemberInfo memberInfo)
   System.Xml.Serialization.TypeScope.GetTypeDesc(Type type, MemberInfo source, Boolean directReference)
   System.Xml.Serialization.TypeScope.GetTypeDesc(Type type, MemberInfo source)
   System.Xml.Serialization.StructModel.GetPropertyModel(PropertyInfo propertyInfo)
   System.Xml.Serialization.StructModel.GetFieldModel(MemberInfo memberInfo)
   System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns)
   System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns)
   System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns)
   System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, Boolean repeats)

[InvalidOperationException: There was an error reflecting type 'chumdata.EntityClasses.ChumFreeStuffEntity'.]
   System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, Boolean repeats)
   System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType)
   System.Xml.Serialization.XmlReflectionImporter.CreateArrayElementsFromAttributes(ArrayMapping arrayMapping, XmlArrayItemAttributes attributes, Type arrayElementType, String arrayElementNs)
   System.Xml.Serialization.XmlReflectionImporter.ImportArrayLikeMapping(ArrayModel model, String ns)
   System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, String ns, Type choiceIdentifierType)
   System.Xml.Serialization.XmlReflectionImporter.ImportMemberMapping(XmlReflectionMember xmlReflectionMember, String ns, XmlReflectionMember[] xmlReflectionMembers)
   System.Xml.Serialization.XmlReflectionImporter.ImportMembersMapping(XmlReflectionMember[] xmlReflectionMembers, String ns, Boolean hasWrapperElement)

[InvalidOperationException: There was an error reflecting 'getFreeStuffResult'.]
   System.Xml.Serialization.XmlReflectionImporter.ImportMembersMapping(XmlReflectionMember[] xmlReflectionMembers, String ns, Boolean hasWrapperElement)
   System.Xml.Serialization.XmlReflectionImporter.ImportMembersMapping(String elementName, String ns, XmlReflectionMember[] members, Boolean hasWrapperElement)
   System.Web.Services.Protocols.SoapReflector.ImportMembersMapping(XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter, Boolean serviceDefaultIsEncoded, Boolean rpc, SoapBindingUse use, SoapParameterStyle paramStyle, String elementName, String elementNamespace, Boolean nsIsDefault, XmlReflectionMember[] members, Boolean validate)
   System.Web.Services.Protocols.SoapReflector.ReflectMethod(LogicalMethodInfo methodInfo, Boolean client, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter, String defaultNs)

[InvalidOperationException: Method wsFreeStuff.getFreeStuff can not be reflected.]
   System.Web.Services.Protocols.SoapReflector.ReflectMethod(LogicalMethodInfo methodInfo, Boolean client, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter, String defaultNs)
   System.Web.Services.Description.SoapProtocolReflector.ReflectMethod()
   System.Web.Services.Description.ProtocolReflector.ReflectBinding(ReflectedBinding reflectedBinding)
   System.Web.Services.Description.ProtocolReflector.Reflect()
   System.Web.Services.Description.ServiceDescriptionReflector.ReflectInternal(ProtocolReflector[] reflectors)
   System.Web.Services.Description.ServiceDescriptionReflector.Reflect(Type type, String url)
   System.Web.Services.Protocols.DocumentationServerType..ctor(Type type, String uri)
   System.Web.Services.Protocols.DocumentationServerProtocol.Initialize()
   System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
   System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)

[InvalidOperationException: Unable to handle request.]
   System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)
   System.Web.Services.Protocols.WebServiceHandlerFactory.CoreGetHandler(Type type, HttpContext context, HttpRequest request, HttpResponse response)

[InvalidOperationException: Failed to handle request.]
   System.Web.Services.Protocols.WebServiceHandlerFactory.CoreGetHandler(Type type, HttpContext context, HttpRequest request, HttpResponse response)
   System.Web.Services.Protocols.WebServiceHandlerFactory.GetHandler(HttpContext context, String verb, String url, String filePath)
   System.Web.HttpApplication.MapHttpHandler(HttpContext context, String requestType, String path, String pathTranslated, Boolean useAppConfig) +699
   System.Web.MapHandlerExecutionStep.System.Web.HttpApplication+IExecutionStep.Execute() +96
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +173

I suppose I could send the thing through an XmlWriter to a string and return that. I guess I thought collections and their decendents were serializable and could be returned through webservices. I may be mistaken. Anyone know?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 13-Oct-2003 11:35:37   

Nice huh, those webservices wink

You've fallen in the same trap as I have: webservices is about XML, not about serialized stuff. The reason for this is that webservices are used to transfer data in a hierarchical way (XML) to other systems which might be running another platform. When you are using .NET as the client platform, you'll see that the client is re-defining all types you return from your webservice, because in theory it doesn't know these types. Webservices in .NET work like this: everything is first transformed to Xml and that Xml is then transfered to the client, and on the client consumed (interpreted, or transformed back to objects)

.NET uses one of the most useless and crappiest designed classes ever (sorry) to create the XML: XmlSerializer. This class is very dumb, it can't work with interfaces (however the SoapFormatter can... go figure). Interfaces are required for a generic framework (MS even uses them a lot). It also requires empty constructors and other things that pollute your code. It is also badly designed because it has a hardcoded codepath for the Dataset class. Why I don't know but it signals me, something fishy is going on behind the scenes because if you need to make an exception for the 'Dataset', more classes are probably not able to be transformed to Xml by this class and cause trouble and probably need to be treated as special classes but MS didn't implement functionality for this: you can implement ISerializable (I have) but that doesn't matter... Also, don't think that when an object is serializable with Soap, it is serializable by a webservices. Apparently the Soap formatter can transform objects to Xml without a problem and can work with interfaces, the XmlSerializer cannot.

Nevertheless, some time ago I wanted to see if I could rewrite the runtime libraries to make it work with XmlSerializer. I couldn't get it to work and till today I don't know what was wrong. I rewrote all classes to work with base classes instead of interfaces. This caused some trouble for the generated code (which was unsolvable) but it was a test to use the XmlSerializer, so I ignored that. When I had rewritten it and wanted to use the objects returned from my webservice I couldn't get it to work because of the re-definition of all my objects. I had to manually change (searched for it on google and MS said in a newsgroup you should do this! frowning ) the generated class file on the client. I also had to define all the types I was returning as 'known types' on the webservice method. This also wasn't very nice. But when I tried to run it, it just 'hang'. The XmlSerializer got caught in an infinite loop and the server ate 10MB of memory away per second.

After 2 days of fighting with that crappy class I gave up. "Webservices is not for easy transportation of object hierarchies between .NET applications" was the conclusion. But now what to do?

---------------------------------------------------------- Solution 1: Remoting. You should use remoting to communicate objects between .NET applications. Below I've pasted 3 blocks of code. Each block is in its own assembly: client, server and interfaces. Interfaces is necessary so server and client use the same interface to communicate with. It's a modified example from the book Programming C# by Jesse Liberty simple_smile

Interfaces:

using System;

using SD.NorthwindDAL.EntityClasses;

namespace Interfaces
{
    public interface IRemoteTest
    {
        CustomerEntity GetCustomer(string customerID);
    }
}

Server:

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using Interfaces;

using SD.NorthwindDAL.EntityClasses;

namespace Server
{
    public class MyServer: MarshalByRefObject, IRemoteTest
    {
        public MyServer()
        {
        }

        public CustomerEntity GetCustomer(string customerID)
        {
            Console.WriteLine("Customer request recieved for customer: {0}", customerID);

            CustomerEntity c = new CustomerEntity(customerID);
            return c;
        }
    }

    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    public class ServerTest
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            HttpChannel chan = new HttpChannel(65100);
            ChannelServices.RegisterChannel(chan);

            Type serverType = Type.GetType("Server.MyServer");
            RemotingConfiguration.RegisterWellKnownServiceType(serverType, "theEndPoint", WellKnownObjectMode.Singleton);

            Console.WriteLine("Press Enter To Exit");
            Console.ReadLine();
        }
    }
}

Client:

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using Interfaces;

using SD.NorthwindDAL.EntityClasses;

namespace RemotingTester
{
    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    class Startup
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            // register http channel
            HttpChannel chan = new HttpChannel(0);
            ChannelServices.RegisterChannel(chan);

            MarshalByRefObject o = (MarshalByRefObject)RemotingServices.Connect(typeof(Interfaces.IRemoteTest),"http://geek:65100/theEndPoint");
            IRemoteTest server = o as IRemoteTest;
            CustomerEntity c = server.GetCustomer("CHOPS");
            PrintCustomer(c);
            Console.ReadLine();
        }


        public static void PrintCustomer(CustomerEntity enCustomer)
        {
            // print the customer object read
            Console.WriteLine("-----[Customer]--------");
            Console.WriteLine("CustomerID: {0}", enCustomer.CustomerID);
            Console.WriteLine("Address: {0}", enCustomer.Address);
            Console.WriteLine("City: {0}", enCustomer.City);
            Console.WriteLine("CompanyName: {0}", enCustomer.CompanyName);
            Console.WriteLine("ContactTitle: {0}", enCustomer.ContactTitle);
            Console.WriteLine("Country: {0}", enCustomer.Country);
            Console.WriteLine("Fax: {0}", enCustomer.Fax);
            Console.WriteLine("PostalCode: {0}", enCustomer.PostalCode);
            Console.WriteLine("Region: {0}", enCustomer.Region);
            Console.WriteLine("\n");
        }
    }
}


---------------------------------------------------------- Solution 2: Serialized text. There is another solution: if you still want to use webservices, you can use the code snippet below. The idea is this: you serialize the objects to a memory stream with Soap. The memory stream contains a string with the Soap data. You can then return the string in that memory stream as the return value of the WebMethod. On the client, create a memory stream from the string and deserialize the objects from the memory stream.

Server:

SoapFormatter formatter = new SoapFormatter();
MemoryStream writeStream = new MemoryStream();
CustomerEntity customer = new CustomerEntity("CHOPS");
formatter.Serialize(writeStream, customer);

string serializedResult = System.Text.Encoding.UTF8.GetString(writeStream.ToArray());
return serializedResult;

Client:

// serializedResult is the return value of the WebMethod called.
MemoryStream readStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(serializedResult));
CustomerEntity customerDeserialized = (CustomerEntity)formatter.Deserialize(readStream);

Remoting is definitely the right choice it's more efficient and It Just Works(tm) simple_smile

Btw: ObjectSpaces, the O/R mapper layer from Microsoft which will be part of .NET 2.0 throws the same exceptions. Let's hope MS solves the XmlSerializer to fix this so we all benefit from this, but I fear the XmlSerializer will get just another exceptional code path, especially for ObjectSpaces...

Frans Bouma | Lead developer LLBLGen Pro
swallace
User
Posts: 648
Joined: 18-Aug-2003
# Posted on: 13-Oct-2003 15:32:20   

What a pain in the patoot. WebServices are my only choice, so that's that route I'll have to go.

Thanks for the great code examples.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 13-Oct-2003 15:45:35   

swallace wrote:

What a pain in the patoot. WebServices are my only choice, so that's that route I'll have to go.

Just out of curiosity, why are webservices your only choice? Because when it comes to .NET <-> .NET, webservices are the worst choice of all, due to the fact that they're a developer burden and very slow. (when you're transfering XML in a given standard format, that's another story).

Frans Bouma | Lead developer LLBLGen Pro
swallace
User
Posts: 648
Joined: 18-Aug-2003
# Posted on: 13-Oct-2003 21:20:50   

I'm unable to control the client. The product is an ASP.NET web application, and I want to create webservice APIs to allow users to publish the gathered data into their own web sites. Those wacky web developers come from all kinds of environments, many of them non- .NET and even non-Windows. I'm looking for the lingua franca, ie, webservices. I don't expect the end-users to actually understand what an EntityCollection is, or to use your product to consume it (sorry). At this point I want to publish out the XML in some standard format and let them work with it on their own site. I guess I thought that serializing the Entity would convert it to XML and let me bang it out the pipe that way.

I've used webservices under .NET extensively in the past, delivering datasets with ease. They are very standard and easily consumed by most non-standard clients. With a non-dataset style collection I have to document more, but that's not so bad.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 13-Oct-2003 21:37:30   

If you just want to convert it to Xml, you can use the .ToXml() method of the entity collection objects simple_smile

I think that will be even better than the soap trick, because the other platforms can't convert it back to an object anyway. I understand now why you picked webservices, and I think you can best return the Xml using the ToXml() method, which converts a complete collection including entities to Xml.

Entities also have a ToXml() method. simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Daniel
User
Posts: 1
Joined: 01-Oct-2004
# Posted on: 01-Oct-2004 22:49:47   

I am trying exactly what you suggested. However, this code:


// .... some code to fetch the collection ... //
XmlNode colXml = col.ToXml();

results in


System.NotSupportedException: Cannot serialize member SD.LLBLGen.Pro.ORMSupportClasses.EntityField.ExpressionToApply of type SD.LLBLGen.Pro.ORMSupportClasses.IExpression because it is an interface.

I'm using the latest release numbered 1.0.2004.1.

Thanks for your help!

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 01-Oct-2004 23:18:49   

Using ToXml() will give you a warning when you compile your code, as it is marked deprecated simple_smile . Use WriteXml() instead. (and return the XmlNode from the webmethod)

Frans Bouma | Lead developer LLBLGen Pro
IowaDave
User
Posts: 83
Joined: 02-Jun-2004
# Posted on: 01-Oct-2004 23:25:14   

I, too, am using webservices and because of the rule we have here to make the front end not coupled to LLBLGen, I've generated custom classes that are used on the client. I also generate a helper class for each llblgen entity, which creates the xml, which is returned to the client and then the custom class has a method that reads through the xml and populates its own properties. I feel I'm doing way too much work here just to get the data across the wire. The architecture decisions here are to use web services, and no llblgen classes on the client, so I'm going to great lengths to create the generic xml from the llblgen entity classes, and reading the xml to populate the llblgen entity classes when I need to write. I think there's a question in here somewhere. It is - is there an easier way to do this and still meet the requirements of 1. using web services and 2. no using LLBLGen on the client?

Thanks, Dave

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 02-Oct-2004 11:24:18   

IowaDave wrote:

I, too, am using webservices and because of the rule we have here to make the front end not coupled to LLBLGen, I've generated custom classes that are used on the client. I also generate a helper class for each llblgen entity, which creates the xml, which is returned to the client and then the custom class has a method that reads through the xml and populates its own properties. I feel I'm doing way too much work here just to get the data across the wire.

I think so too. What you should do is use the WriteXml() method build into the entity classes to produce XML. Then, you copy the code of ReadXml() from the runtime lib source and build your Xml reader from that. The Xml produced by WriteXml() is very straightforward and easy to understand. There is one tag which needs attention, the tag which is the placeholder for a cyclic reference. But that's it.

The architecture decisions here are to use web services, and no llblgen classes on the client, so I'm going to great lengths to create the generic xml from the llblgen entity classes, and reading the xml to populate the llblgen entity classes when I need to write. I think there's a question in here somewhere. It is - is there an easier way to do this and still meet the requirements of 1. using web services and 2. no using LLBLGen on the client?

Well, I think you just need a consumer routine on the client which understands the easy Xml produced by WriteXml(). That routine is already there, in the orm support classes, so you can base your routine on that code. You can probably skip a lot of code in that routine, as you probably only need the Fields data.

Frans Bouma | Lead developer LLBLGen Pro
Fabrice
User
Posts: 180
Joined: 25-May-2004
# Posted on: 02-Oct-2004 16:29:09   

I also use webservice, and on solution design we decide to not use llblgen object on the client side. The webservice had to be consumed by different type of client (.NET SmartClient and web site in php) So I wrote a DataSetGenerator, a piece of code that transform an entity (or entitycollection) to a dataset. So we use typed dataset as return type of our webmethod. Of course I also wrote an EntityGenerator to transform a typed dataset into a (collection of) entity (and keep all related object, new/dirty/deleted state etc).

Reflection powaaaa simple_smile

PS : I've not use the WriteXML() method, because it's the only point of llblgen I don't like (take too much time, and generated XML is very very larger than dataset xml.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 02-Oct-2004 17:45:50   

The xml is verbose, but it contains true type information for each field. This is important when you store the data somewhere or you want to use it in whatever system, other than a dataset container.

Frans Bouma | Lead developer LLBLGen Pro
IowaDave
User
Posts: 83
Joined: 02-Jun-2004
# Posted on: 04-Oct-2004 22:30:38   

Well, I think you just need a consumer routine on the client which understands the easy Xml produced by WriteXml(). That routine is already there, in the orm support classes, so you can base your routine on that code. You can probably skip a lot of code in that routine, as you probably only need the Fields data.

I agree I just only need the fields. I am curious why Fabrice is saving all the flags - is dirty etc. This being truly stateless, the data should be the only thing in the entity class of interest. If the web method is aware of whether it's an update or insert method, I should be able to create a new instance of the entity and populate the data, set the is new or not new depending on which method and do a save. Correct?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 04-Oct-2004 22:38:04   

Correct simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Fabrice
User
Posts: 180
Joined: 25-May-2004
# Posted on: 05-Oct-2004 15:22:30   

I don't put all llblgen properties in the dataset As I work by reflection, it's quite simple to do : I only take fields defined in the generated classes, not the fields declared in the class above (IEntity2). And if I want to add a field, It'll be directly present in the dataset In the other direction (dataset -> entity), with the RowState you know how to set the IsNew & isDirty flags (and I add an isDeleted flags)

Otis wrote:

The xml is verbose, but it contains true type information for each field. This is important when you store the data somewhere or you want to use it in whatever system, other than a dataset container.

Yes, I fully agree, but when it's not needed, it's quite useless to have the same data (field type for each entity) take a lot of place. The dream is to have the choice wink

IowaDave
User
Posts: 83
Joined: 02-Jun-2004
# Posted on: 05-Oct-2004 15:47:11   

Oh, I see what you are doing, which makes sense since you've decided to return/pass datasets. We have a rule here that we won't return any .NET-only data types (eg Datasets) This is based on the theory that the return value (the xml) should be generic so the front end can be a non-.NET client. This is based on the fact that we have products(applications) in our company that are java, etc and a desire to make everything as open as possible. These contraints create a lot of extra work, it's true.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 05-Oct-2004 16:21:12   

Fabrice wrote:

I don't put all llblgen properties in the dataset As I work by reflection, it's quite simple to do : I only take fields defined in the generated classes, not the fields declared in the class above (IEntity2). And if I want to add a field, It'll be directly present in the dataset In the other direction (dataset -> entity), with the RowState you know how to set the IsNew & isDirty flags (and I add an isDeleted flags)

You can also just traverse the Fields object to grab the fields of an entity, no need for reflection simple_smile

Otis wrote:

The xml is verbose, but it contains true type information for each field. This is important when you store the data somewhere or you want to use it in whatever system, other than a dataset container.

Yes, I fully agree, but when it's not needed, it's quite useless to have the same data (field type for each entity) take a lot of place. The dream is to have the choice wink

You'd opt for a more lightweight XML producing method overload?

Frans Bouma | Lead developer LLBLGen Pro
Fabrice
User
Posts: 180
Joined: 25-May-2004
# Posted on: 05-Oct-2004 17:35:03   

Otis wrote:

You can also just traverse the Fields object to grab the fields of an entity, no need for reflection simple_smile

I agree but reflection is needed - in case I add new property (computed property for example) to the entity (I work with derived entities). This property will not be in the fields list. - to add pk and fk in the generated dataset

Otis wrote:

You'd opt for a more lightweight XML producing method overload?

Exactly ! But .. for me it's allready too late, I can't change that so close to the release wink

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 05-Oct-2004 18:05:22   

Fabrice wrote:

Otis wrote:

You can also just traverse the Fields object to grab the fields of an entity, no need for reflection simple_smile

I agree but reflection is needed - in case I add new property (computed property for example) to the entity (I work with derived entities). This property will not be in the fields list. - to add pk and fk in the generated dataset

Good points simple_smile

Otis wrote:

You'd opt for a more lightweight XML producing method overload?

Exactly ! But .. for me it's allready too late, I can't change that so close to the release wink

I'll see what I can come up with in the future, I'll add it to the todo list. (although I really hate XSchema...)

Frans Bouma | Lead developer LLBLGen Pro
Fabrice
User
Posts: 180
Joined: 25-May-2004
# Posted on: 05-Oct-2004 18:22:46   

IowaDave wrote:

Oh, I see what you are doing, which makes sense since you've decided to return/pass datasets. We have a rule here that we won't return any .NET-only data types (eg Datasets) This is based on the theory that the return value (the xml) should be generic so the front end can be a non-.NET client. This is based on the fact that we have products(applications) in our company that are java, etc and a desire to make everything as open as possible. These contraints create a lot of extra work, it's true.

We are consuming the webservice with a .NET client yes, but also with a php website (and more external client in the future). DataSet are maybe a .NET element, but it's firstly XML so it's not difficult to make a XML parser for dataset, as you will do for the "normal" XML. But I understand your point of view. We have discussed a lot before choosing (typed) dataset.