We've recently upgraded from the CSLA 3.5 to 3.6.Latest and .NET Remoting does not appear to be working correctly. There are actually 2 issues going on:
1.) Trying to generate WSDL is throwing an exception:
http://localhost/remotinghost/remotingportal.rem?wsdl
Generates:
System.NullReferenceException: Object reference not set to an instance of an object. at System.Runtime.Remoting.MetadataServices.WsdlGenerator.RealSchemaType.PrintMessageWsdl(TextWriter textWriter, StringBuilder sb, String indent, ArrayList refNames) at System.Runtime.Remoting.MetadataServices.WsdlGenerator.XMLNamespace.PrintMessageWsdl(TextWriter textWriter, StringBuilder sb, String indent, ArrayList refNames) at System.Runtime.Remoting.MetadataServices.WsdlGenerator.PrintWsdl() at System.Runtime.Remoting.MetadataServices.WsdlGenerator.Generate() at System.Runtime.Remoting.MetadataServices.MetaData.ConvertTypesToSchemaToStream(ServiceType[] serviceTypes, SdlType sdlType, Stream outputStream) at System.Runtime.Remoting.MetadataServices.SdlChannelSink.GenerateSdl(SdlType sdlType, IServerResponseChannelSinkStack sinkStack, ITransportHeaders requestHeaders, ITransportHeaders responseHeaders, Stream& outputStream) at System.Runtime.Remoting.MetadataServices.SdlChannelSink.ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, IMessage& responseMsg, ITransportHeaders& responseHeaders, Stream& responseStream) at System.Runtime.Remoting.Channels.Http.HttpHandlerTransportSink.HandleRequest(HttpContext context) at System.Runtime.Remoting.Channels.Http.HttpRemotingHandler.InternalProcessRequest(HttpContext context)
If we roll back to version 3.5.X, I receive the WSDL just fine.
2.) I'm assuming that this issue is tied to an issue that we're having regarding inheritance and invalid casting due to type mismatch cast exceptions when setting or retrieving values from FieldManager (GetProperty and SetProperty). We have addressed these issues with the 'dummy' variables as recommended in the other posts, but it is still not working under 3.6 when using .NET Remoting.
Anyone have any issues with this or is the development team aware of this issue?
Thanks!
I see the same WSDL problem, though I don't know the cause.
The only meaningful change to remoting in the past few years is that the Delete() method now accepts an optional generic parameter like Create() and Fetch().
I must confess that I haven't been using (or testing) anything beyond the WCF channel for a while now. That's probably not good, but it is somewhat hard to imagine why anyone would choose to use remoting :)
I'll add this to the bug list.
Hahah, I know, I know. I've been swamped with other learning activities (ie WPF and your latest framework ;) and haven't had a chance to figure out how to set up the WCF channel yet. I'll get there.
Any ideas on #2? Unfortunately we have already converted all of our GetProperty and SetProperty methods to go without specifying generic types, and I don't want to revert back to it (that would take hours). Is that something that you can easily test on your end?
Thanks again!
I don’t understand the issue with number 2?
It's regarding this issue:
http://forums.lhotka.net/forums/thread/26402.aspx
If I run my code against local dataportal, it works. However, running against remoting server, the index of the items don't match up, and I get type conversion errors. In each subclass, I have implemented created the static dummy field and initialized it to 0. This initialization occurs both in the constructor and OnDeserialized() in each subclass.
Does that make sense?
That doesn’t sound like the same issue – hence my
confusion.
If the RegisterProperty() calls don’t work you’ll
get null ref exceptions or property not registered exceptions.
If I understand you correctly, you are getting some sort of
casting or type mismatch exception?
Rocky
Sorry for any confusion, I thought it was the same issue. Here's what's happening in detail:
Here is my class hierarchy ClassB --> ClassA --> BusinessBase
Within ClassA...
private static PropertyInfo<string> SomeValueProperty = RegisterProperty(new PropertyInfo<string>("SomeValue")); public string SomeValue{
get { return GetProperty(SomeValueProperty); } set { SetProperty(SomeValueProperty, value); }}
Here is the affected statement:
ClassA.SomeValue = "I'm a string";
What's happening is that when SetValue() within the setter{} is called, it calls FieldManager.GetFieldData(propertyInfo). Within GetFieldData(), it uses the index of the property to retrieve the field from _fieldData (_fieldData[prop.Index]). The problem is, it's retrieving the wrong field because the _fieldData array does not contain the count that it should contain.
So in my specific scenario, passing "SomeValueProperty" in retrieves the field "SomeOtherIntegerProperty" of type int instead of "SomeValueProperty" because the indexes don't match.
This code works fine if going against my local portal, but when using the remoting portal is when it's problematic. I am positive that the .dll's in the remoting bin folder and in my project are the same as well.
Does this make sense? I realize this might be confusing, but hopefully you've seen this or are able to reproduce it.
Thanks again!
It does sound like a different set of symptoms from the same
problem. Interesting that this is the first encounter with this symptom.
Can you please use the debugger and ensure that the
OnDeserialized() method is being invoked as we expect – on the client
when the object graph comes back from the server?
My suspicion is that it isn’t being called, so the static _forceInit
(or _dummy) field isn’t being set on deserialization – on either
the server or the client, one of the two.
Thanks!
Rocky
Yes, OnDeserialized() is being invoked, and it is overriden in each subclass as recommended. We thought maybe having the private constructor set the _dummy value was an issue too, but no luck there.
Aaron
And you do the force init in every one of your classes?
Not just the leaf node class, but the base classes too?
From: AaronH
[mailto:cslanet@lhotka.net]
Sent: Thursday, December 04, 2008 8:52 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: RE: 3.6 version breaks remoting
support?
Yes, OnDeserialized() is being invoked, and it is overriden in each subclass
as recommended. We thought maybe having the private constructor set the
_dummy value was an issue too, but no luck there.
Aaron
Ok, so as it turns out, I believe the issues to be unrelated. The remoting still works, but here's what I had to do (which I'm terribly embarrassed about not catching in first place):
private static int _forceInit;
private New() : base()
{
_forceInit = 0;
}
protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
{
_forceInit = 0;
base.OnDeserialized(context);
}
It's important to call the base constructor and method all the way down the inheritance chain. I was so rushed when finding the initial solution to the _dummy fix that I just copied and pasted what I found in a previous post, which didn't include the calls to base.
So to wrap things up: I'm still getting the issue when requesting the wsdl, however, I'm able to successfully use .NET Remoting in conjunction with CSLA 3.6.Latest and a 4 level inheritance hierarchy.
Thanks for all of your ideas!
Aaron, I’m glad you found the answer!!!
I did add the wsdl issue to the bug list – though it falls
below the threshold for fixing before RTW of 3.6 since remoting actually does
work regardless.
Rocky
RockfordLhotka:
I must confess that I haven't been using (or testing) anything beyond the WCF channel for a while now. That's probably not good, but it is somewhat hard to imagine why anyone would choose to use remoting :)
I don’t believe the problem is due to remoting. I suspect
there’s a missing bit of code to trigger static field initialization on
either server or client. I’m seriously considering adding a bit of
reflection code to avoid this static field issue. Unfortunately I can only do
so in .NET, because in SL the reflection is too limited. So the use of
_forceInit appears totally unavoidable in SL L
To answer your question about switching to WCF, the answer is
that it is purely a config thing – from the CSLA perspective.
You simply need to do this:
1.
Upgrade your server to .NET 3.5 SP1 (assuming CSLA 3.6)
2.
Add a svc file to your data portal host web site
3.
Add a few lines of config to web.config – mostly boiler-plate
Now your server is ready to go. Then you do this on the client:
1.
Add a few lines of config to app.config – mostly boiler-plate
2.
Change the CslaDataPortalProxy to use the WcfProxy
That should be it.
The only caveat I’ll throw out, is that WCF has a
bajillion configuration options. Actually getting it configured and running in
a production setting can take some time, because you need to get all the
options set as you need them. The big help with this is that Microsoft Patterns
and Practices put a guidance book on codeplex a while back, and it is invaluable
in getting WCF properly configured.
That’s not really a CSLA thing – the steps above
will make CSLA happy – it is a WCF thing.
Rocky
Actually, I suspected that WCF setup would be easy as the only thing that truly differs (aside from config settings) is the addition of the .svc file. I managed to create a local web application in IIS (7.0), copy the PTracker WcfHost files into that, and point the PTracker WPF app config to it. Worked without a hitch.
I then copied my project's remoting host contents into a new web app, and created the svc file. Pulled up the svc file in the browser without a hitch.
BUT, we're using Windows Authentication, not CSLA, and I received the CommunicationException:
The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.
I'm not looking for you to debug this for me, just wanted to point out that moving from .NET Remoting to WCF is not as easy as it seems (without having a decent grasp on WCF and authentication).
Of course, if you're familiar with this issue and have a quick fix that you can share, I'll accept it :)
RockfordLhotka:
I’m seriously considering adding a bit of reflection code to avoid this static field issue. Unfortunately I can only do so in .NET, because in SL the reflection is too limited. So the use of _forceInit appears totally unavoidable in SL L
Rocky
Please do. I am about to upgrade to 3.6 and I hate the idea of tweaking every single class in a deep inheritance hierarchy to deal with this issue.
Joe
My only fear with this, is that it will introduce a difference between .NET and SL that could cause confusion. People with .NET classes that move to SL would need to go add the _forceInit code throughout, because there's simply no way to get SL to reflect against private fields.
To be clear, the reflection I'm talking about is a bit of code that would trigger in the field manager on the very first request for the property list for a given type. The code would loop through each type in the inheritance hierarchy, reading one static field value from each type (which ever one it finds first).
This should have no meaningful perf impact, and would solve the _forceInit issue rather entirely. But it only works if you can reflect against a static field - which you can't in SL :(
JoeFallon1:
RockfordLhotka:
I’m seriously considering adding a bit of reflection code to avoid this static field issue. Unfortunately I can only do so in .NET, because in SL the reflection is too limited. So the use of _forceInit appears totally unavoidable in SL L
RockyPlease do. I am about to upgrade to 3.6 and I hate the idea of tweaking every single class in a deep inheritance hierarchy to deal with this issue.
Joe
Copyright (c) Marimer LLC