This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
Hello -
I am trying to get the new LS 4 beta running, and really looking forward to using it. If it works, it should save me endless ours of "glue" code trying to make DTOs do what I want them to do... In the blog you state "On the server end, this is hosted by using the DistributedUnitOfWorkService which uses a WCF endpoint which you can configure according to your endpoint’s requirements to handle the requests." How do I use this? Do my services need to inherit from DistributedUnitOfWorkService? On a related note, your DTOs sample includces 2 files I have been using in my services - ServiceBase.cs and ServiceExtensions.cs - are these needed with the new beta? Do they even work? It looks like ServiceBase handles generating the UnitOfWork, so that may change, and ServiceExtensions references the UnitOfWork as well. Do you guys have a small bit of sample code for setting up a service using the new DistributedUnitOfWorkService? That would be awesome... Thanks, Dave
|
|
|
Hi Dave, The sample attached this thread should give you a good start on the DistributedUnitOfWork and Service bits: http://www.mindscapehq.com/forums/Thread.aspx?ThreadID=3900 , you wont need those older Service/ServiceExtensions files with the newer bits. Please fire back any questions you have :) Hopefully the answers to the above should be covered in the attached example regarding what code you need to write etc.
Jeremy
|
|
|
Thanks for the example. I have successfully implemented the host side of my test service using your example as a template -- at least it complied and started. When I tried to navigate to my service from a browser, I got the following exception: System.InvalidOperationException: An exception was thrown in a call to a WSDL export extension: System.ServiceModel.Description.DataContractSerializerOperationBehavior A quick search online tells me I need to use the CollectionDataContract attribute instead of the DataContract attribute (see http://blog.ecofic.com/?p=395 and http://msdn.microsoft.com/en-us/library/system.runtime.serialization.collectiondatacontractattribute.aspx). Since LightSpeed generates the attributes, I am at a loss as to how to get past this error. Now for the client side... From what I know about WCF, I need to generate a proxy on the client side to communicate with any given service. However, it doesn't appear you have done so in the example. Does the DistributedUnitOfWork take the place of the proxy in some way? How does this work without a service reference? Please enlighten me on how things work on the client side, thanks! Dave
|
|
|
Yuch! Not sure what happened to the formatting on that last post, but it's all there in the email that was generated for me. Sorry about that! Dave
|
|
|
Hello again - According to my calculations, if you come to work at all today you should be in before long... I do have one other problem with the DistributedExample you provided -- there is no database, and I am unable to generate one from the model, as I hoped I would be able to. Is it possible for me to get a SQL script to generate the database so I can actually see the sample work, and see how it compares to my test database? Thanks so much for your help, Dave |
|
|
Yes, you dont need to create a proxy yourself, instead you will use a DistributedUnitOfWork, the way this is created is by specifying the factoryClass on the LightSpeedContext configuration - e.g in app.config you will find: factoryClass="Mindscape.LightSpeed.ServiceModel.DistributedUnitOfWorkFactory, Mindscape.LightSpeed.ServiceModel" This means that this factory is used to create the UnitOfWork instances. In the example we are creating a typed UnitOfWork, if you have a look at the definition of that class you will see it inherits from DistributedUnitOfWork and contains the LINQ IQueryable properties as per our other generated typed UnitOfWork instances. public class DistributedModelUnitOfWork : DistributedUnitOfWork, IModelUnitOfWork { } The value in the DistributedUnitOfWork is that it gives you a client side UnitOfWork instance to work with as if you were programming on the server, and we manage getting the data to and from the service endpoint. If you were creating a custom service and returning EntityCollection instances over that then ensure you are using the NetDataContractSerializer for any EntityCollections you are exposing - there is an attribute available in the Mindscape.LightSpeed.ServiceModel assembly to help with this and you can use it to decorate the applicable service operations. e.g. from the example, INewsContract.cs: [ServiceContract]
Hope that helps, Jeremy |
|
|
Here is a quick schema dump for that database - when creating via the model make sure you update the DatabaseProvider and ConnectionString properties on the model accordingly to point it to your local database :) -- Add table Section to the database |
|
|
Hi Jeremy - I tried the UseNetDataContractSerializer attribute, to no avail. I get the same error when trying to browse the URL. I think I may have to enable the metadata exchange for this to work anyway, so I'll save that project for another day. I'm used to the screenful of information you get when using strongly typed datasets... I do have the server and client working, after a fashion, but I'm getting a socket timeout, and the trace output from the server seems to indicate the service is doing far more than I asked it to. I'll try to give you enough to explain what is happening without being too verbose. As an aside, do I need to expose the DistributedModelUnitOfWork at all? I prefer creating the methods on the server and just calling the methods from the client, not embedding table-level LINQ queries in the client code. Anyway...
In the model/database, there is a tester with an Id, Name and other fields. There is also a TestResult that references the Tester by its Id. On the server, I have this (stripped-down) method: public Tester GetTesterByInitials( string inits ) |
|
|
The extra fetch is likely due to your TestResults being eager loaded as per your model. If you dont want this, then turn off the eager load for that association (or set the eager load to be based on a named aggregate instead). The error you are getting from WCF sounds like you need to increase the maxMessageSize on your binding. One of the things which I use to help track down whats actually going on with those WCF errors is to use the tracing, you will notice on the DistributedExample app the app.config for client and server both have the diagnostics configured. If you change the location of the sharedListener's output file to be a valid local path then you will start getting trace files written. You can then open them up and drill down on what the problem is, I suspect in this case that it will be that the response message is larger than allowed by the binding so the channel just gets closed down. WCF error messages out of the box are very unhelpful unfortunately! But the tracing is very good for tracking this stuff down :)
Jeremy |
|
|
Thanks for the reminder about eager loading/ I guess I never realized it could be quite THAT eager...
I found and inspected the trace logs -- no help there. The client says "see server logs for more details", and the server just repeats the same info that was reported in the error message. Both ends claim the other end is not using the HTTP protocol, so I probably have some obscure error in the config files. I'll keep working with it and see what I can come up with. Thanks fo the help! Dave |
|
|
OK, I checked (in the designer) and both the Eager Load Backreference and Eager Load Collection are set to False, but it is still trying to load the TestResults when all I want is the Tester record. I changed the binding on both ends to netTcpBinding (and also changed the URLs to match), and got a little more info, but now it just claims the socket was closed. The first error on the service side tells me the failure was trying to load the collections for TestResult (invalid collection type, as mentioned before) -- but I don't want that loaded, and I didn't ask for it to be loaded. I also didn't decorate that method, as I don't want a collection to be returned... however, when I did use the UseNetDataCOntractSerializer attribute, it worked! Now, why am I getting eager loading when I don't want it? Where else should I be looking? Thanks, Dave |
|
|
Is the collection decorated with a [DataMember] attribute?
Jeremy |
|
|
Yes it is, in the Model.cs file. I am leaving for the night, and this is your Friday, so if we don't figure this out I will just work with it as is for now. I can continue with the rest of what I need to do if I just treat everything as being eager loaded until we figure out how to prevent it from being so. I'm confident we can resolve this next week. I love the improvements, this will make my work so much easier -- once I get it all figured out, that is... Have a great weekend! Dave |
|
|
Right, that will be the issue then :) You will want to update that to remove the [DataMember] declaration to avoid that association being included in the response (and traversing it is what will be causing the lazy load fetch of the entities which you saw in the SQL output). Have a great weekend!
Jeremy |
|
|
That works! However, there has to be a way to do that from the designer, right? I mean, if I edit the designer-generated code, then the next time I make a change to the designer I will most likely lose that change, right? This is a common scenario. In my test database alone, where I only have 7 entities (including the through association entity) I have 3 cases where I don't want the collection loaded and have to edit the auto-generated code to prevent this from happening. I'm not sure what you want to call it, but this functionality needs to have designer support. Here's a great example: In the case we are talking about here I have maybe 10 testers (employees) that are authorized to run tests on the product we produce. That's the final step in the production process, and only line leads should be doing this. There is a one-to-many relationship from the tester record to the tests they have performed. When I load a test, I DO want to know who the tester was, so I want the Tester record loaded along with the TestResult record. However, when I look up information on the tester, or verify the employee is authorized to run the test (does the record exist), I definitely do NOT want every test they have ever performed loaded. Similarly, we will have several TestPlan records, and every TestResult will reference one of these TestPlan records. If I want to get a list of all currently active test plans, I most definitely do NOT want every test run using those test plans returned. That's nearly the entire database! So I may have written all this for nothing if you already have designer support for this, but I couldn't find it. Let me know what you think... Thanks for the awesome product! Dave |
|
|
For now you will need to update the templates in C:\Program Files\Mindscape\LightSpeed\Tools\Designer\Templates\C# (assuming default install location and that you are using C#, change as required). If you edit RelationshipProperties.vm and remove the [DataMember] attribute declarations then you can remove those from the generation. Going forward Ill have a look at getting some support added in to the designer if possible to control these more granularly.
Jeremy |
|
|
Jeremy - Thanks for the tip. I will copy the template files locally and point to the edited templates in my model, and see what happens. I am still concerned, though. You seem to be setting up the relationships as always being a 2-way "has-a", or "contains" relationship. For example, a TestResult "has a" Tester associated with it, but the Tester-to-TestResult relationship is more like "is contained by", for lack of a better term. Yet, both ends of the relationship, as modeled in model.cs, declare the relationship as DataMember. This is almost never correct... I have situations where I want the DataMember attribute to be there -- when a TestResult has a collection of Devices that were tested, for example -- but I don't necessarily want the reverse relationship modeled as a DataMember in this case. This is the same relationship as before (one-to-many), but in this case, I want the collection returned every time. Editing the templates will eliminate that desired relationship along with the undesired ones, unless I'm missing something critical, and I'm right back to editing model.cs... One idea for incorporating this into the designer might be to have some way to model the concept of direction, so the designer would know to generate the DataMember attribute for this end and not that end, or vice versa. This is getting long, and I apologize for that. However, this point is critical to the success and usability of the new LightSpeed release. Everything I know tells me it is very bad practice to edit auto-generated code, e.g. the model.cs file. It's also a pain in the rear, and something that needs to be carefuly documented and checked with every iteration of the model. In summary, I feel it needs to be fixed. I will soldier on and edit the model.cs file for now, but I really do feel this is an important point and needs to be addressed. Your product is too good not to do so... Thanks, Dave |
|
|
Jeremy - I just went through and looked at every relationship in my full data model, and it seems there are some cases where having the collection loaded no matter which entity I was retrieving is acceptable, but still not necessary. In the vast majority of cases, however, only one direction is desirable or acceptable. This means I will be editing nearly every entity in model.cs, regardless of whether I edit the template or not. Unfortunately the collection loaded is not dependent on how the relationship is defined in the database. It is more dependent on the logical model of the data, not the database implementation of the relationship, so I still feel there needs to be some way of telling the designer how you want the relationship to be modeled. Thanks again, Dave |
|