Duplicate class definitions

J

Jeff Johnson

Disclaimer: I am extremely new to Web services and may very well be doing
the wrong thing!

Background: I have a Web service and a Windows Forms client app (VS 2005).
The Web service exposes a method to accept a ScheduleEntry object, which is
a class I have written. I felt doing this would be cleaner than passing 7 or
8 parameters, but I've run into some problems.

First, I learned that declaring classes in Web services isn't such a great
idea because the proxy class you get in your client app when you make a Web
reference only has properties and not methods.

So I decided that I'd move my class definition to a separate assembly that
I'd then reference in both the Web service and my app. This sort of works,
but now I'm getting a separate definition of the class through the Web
service. This is hard to explain so I'll give an example.

---------------
1. Assembly which contains my class (we'll call it "Scheduling.dll.")

namespace Main.Name.Space
{
public class ScheduleEntry
{
// Stuff
}
}
---------------
---------------
2. Web service

[WebService(Namespace = http://www.mycompany.com/schedulerservice)]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class SchedulerService : System.Web.Services.WebService
{
[WebMethod]
public int AddScheduleEntry(ScheduleEntry schedule)
{
// Stuff
}
}
---------------
---------------
3. Client app

This app contains a Web reference which I named "Scheduler" and a regular
reference to Scheduling.dll. It uses the same namespace as Scheduling.dll
(i.e., Main.Name.Space). I can see that this namespace contains a class
known as Main.Name.Space.ScheduleEntry. However, when I create an instance
of Scheduler.ScheduleService and look at the signature of the
AddScheduleEntry() method, the parameter is identified as
Main.Name.Space.Scheduler.ScheduleEntry and I can't pass a
Main.Name.Space.ScheduleEntry object because the compiler complains that it
can't cast between those types.

Is there any kind of decoration I need to do in the Web service so that when
the WSDL is interrogated and the proxy built in my client the ScheduleEntry
class comes out with the proper namespace?
 
R

RYoung

I think the way services are developed in WCF might help gain some insight
into this:

[DataContract]
class ScheduleEntry
{
public string EntryTitle;
public DateTime Timestamp;
}

[ServiceContract]
class Scheduler
{
[OperationContract]
public void AddEntry(ScheduleEntry entry)
{
}
}

The point is that the data (ScheduleEntry) is separate from the
operations/behaviors/methods that act on that data (Scheduler).

Your web service is the "point of contact" to communicate with when your
client app wants operations performed on some ScheduleEntry data. So, other
than any local processing, your client doesn't need a ScheduleEntry object
that has behavior, because the service is the behavior.

That being said, there's no need to reference the Scheduler.dll in your
client application.

Your 100% correct in wrapping a group of parameters into a single object
(ScheduleEntry) and even factoring that and other similiar objects into a
separate assembly.

Your service references that assembly, because that contains the information
it exchanges and accepts.

In essence, your service says "give me a schedule ID, and I'll send you back
a ScheduleEntry for that ID", and "give me some ScheduleEntry data, and I'll
insert it, update it".

Does that make any sense? What I want to get at here, is I think your
approach is incorrect in as far as the client app referencing an assembly in
order to use the behaviors of objects in that assembly and where those
objects are types being used in the service.

For instance:

MyMath.dll

class Math
{
public int X, Y;
public void Add(){ return X + Y; }
}

Service.dll
[WebService]
public MyMath.Math GetMath()
{
return new MyMath.Math();
}

You know what the client will get, a Math object with X and Y fields. If you
wanted to get a Math object hat had behavior, you'd have to do .NET Remoting
and have Math derive from MarshalByRefObject, and then your still not
getting a Math object that can Add() locally. When Add() is called on that
remoted object, the call will go across the network to the instance of Math
that the remoting server created and is keeping alive for you.

The following would more accurately represent a "math" service:

DataTypes.dll
class Numbers
{
public int X, Y;
}

BusinessComponent.dll
class Math
{
public int Add(Numbers numbers){ return numbers.X + numbers.Y; }
}

MathService.dll
class MathService
{
public int Add(Numbers numbers)
{
return new Math().Add(numbers);
}
}

The MathService is a wrapper around existing functionality so that the
functionality can be reachable over network protocols.

Well, I won't go on, but will point out some things that may help:
http://www.thinktecture.com/Resources/Software/WSContractFirst/default.html
- scroll down to the "walkthrough" link. It may also address sharing data
definitions among projects (which is different that sharing objects with
behavior).

I highly suggest downloading that tool, going through the walkthrough a
couple times, then try applying it to your project. I'm almost 100% certain
it will change the way you think about services, for the better.

Ron

Jeff Johnson said:
Disclaimer: I am extremely new to Web services and may very well be doing
the wrong thing!

Background: I have a Web service and a Windows Forms client app (VS 2005).
The Web service exposes a method to accept a ScheduleEntry object, which
is a class I have written. I felt doing this would be cleaner than passing
7 or 8 parameters, but I've run into some problems.

First, I learned that declaring classes in Web services isn't such a great
idea because the proxy class you get in your client app when you make a
Web reference only has properties and not methods.

So I decided that I'd move my class definition to a separate assembly that
I'd then reference in both the Web service and my app. This sort of works,
but now I'm getting a separate definition of the class through the Web
service. This is hard to explain so I'll give an example.

---------------
1. Assembly which contains my class (we'll call it "Scheduling.dll.")

namespace Main.Name.Space
{
public class ScheduleEntry
{
// Stuff
}
}
---------------
---------------
2. Web service

[WebService(Namespace = http://www.mycompany.com/schedulerservice)]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class SchedulerService : System.Web.Services.WebService
{
[WebMethod]
public int AddScheduleEntry(ScheduleEntry schedule)
{
// Stuff
}
}
---------------
---------------
3. Client app

This app contains a Web reference which I named "Scheduler" and a regular
reference to Scheduling.dll. It uses the same namespace as Scheduling.dll
(i.e., Main.Name.Space). I can see that this namespace contains a class
known as Main.Name.Space.ScheduleEntry. However, when I create an instance
of Scheduler.ScheduleService and look at the signature of the
AddScheduleEntry() method, the parameter is identified as
Main.Name.Space.Scheduler.ScheduleEntry and I can't pass a
Main.Name.Space.ScheduleEntry object because the compiler complains that
it can't cast between those types.

Is there any kind of decoration I need to do in the Web service so that
when the WSDL is interrogated and the proxy built in my client the
ScheduleEntry class comes out with the proper namespace?
 
S

Shailen Sukul

Well the *correct* way to do this is to extend the proxy generator behaviour
to recognize your types when the proxy code is generated.

This is not as straightforward as it could be and the easier way to do this
would be to edit the proxt class code after generation and manually point
the business object to yours. However, keep in mind that this code will get
overwritten everytime the proxy generator is invoked.

The correct way to do it would be:

1. Create a type that inherits from SchemaImporterExtension
2. Override the ImportSchemaType method
3. Write code to check the name and namespace of the type described in the
WSDL document and replace with your own type and return the generated code.
4. Give your type a strong name and put it in the GAC (alternatively put it
in the bin folder)
5. Register the extension to the proxy generator in the machine.config
6. Use Add Web Reference or wsdl.exe to generate the proxy.

HTH.

--
With Regards
Shailen Sukul
..Net Architect
(MCPD: Ent Apps, MCSD.Net MCSD MCAD)
Ashlen Consulting Services
http://www.ashlen.net.au
Jeff Johnson said:
Disclaimer: I am extremely new to Web services and may very well be doing
the wrong thing!

Background: I have a Web service and a Windows Forms client app (VS 2005).
The Web service exposes a method to accept a ScheduleEntry object, which
is a class I have written. I felt doing this would be cleaner than passing
7 or 8 parameters, but I've run into some problems.

First, I learned that declaring classes in Web services isn't such a great
idea because the proxy class you get in your client app when you make a
Web reference only has properties and not methods.

So I decided that I'd move my class definition to a separate assembly that
I'd then reference in both the Web service and my app. This sort of works,
but now I'm getting a separate definition of the class through the Web
service. This is hard to explain so I'll give an example.

---------------
1. Assembly which contains my class (we'll call it "Scheduling.dll.")

namespace Main.Name.Space
{
public class ScheduleEntry
{
// Stuff
}
}
---------------
---------------
2. Web service

[WebService(Namespace = http://www.mycompany.com/schedulerservice)]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class SchedulerService : System.Web.Services.WebService
{
[WebMethod]
public int AddScheduleEntry(ScheduleEntry schedule)
{
// Stuff
}
}
---------------
---------------
3. Client app

This app contains a Web reference which I named "Scheduler" and a regular
reference to Scheduling.dll. It uses the same namespace as Scheduling.dll
(i.e., Main.Name.Space). I can see that this namespace contains a class
known as Main.Name.Space.ScheduleEntry. However, when I create an instance
of Scheduler.ScheduleService and look at the signature of the
AddScheduleEntry() method, the parameter is identified as
Main.Name.Space.Scheduler.ScheduleEntry and I can't pass a
Main.Name.Space.ScheduleEntry object because the compiler complains that
it can't cast between those types.

Is there any kind of decoration I need to do in the Web service so that
when the WSDL is interrogated and the proxy built in my client the
ScheduleEntry class comes out with the proper namespace?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top