.NET WebService WebMethod with custom object as Parameter - c#

I have created a .NET WebService. There I have implemented the following WebMethod:
[WebMethod]
public string CheckLicense(License license) {
return "";
}
The Type License comes from a different Assembly X which I have referenced to the WebService. The Fulltype of License is Prayon.Shared.Library.Licensing.License
Now, I have build a client which also references the Assembly X. When I try no to call the WebService with CheckLincense:
private void CheckLicense(License license) {
using(var service = new Prayon.Service.Web.PrayonService()) {
service.CheckLicense(license);
}
}
There service.CheckLicense() want an object of Type Prayon.Service.Prayon.Service.Web.License.
I don't know what I am doing wrong. What does I have to do, that I can pass a object of Type Prayon.Shared.Library.Licensing.License to service.CheckLicense()?

If you want to use a method in your License object you need to :
Call your WebService, obtain a service.License object, use it to create an instance of your local License object, after that you will have your 'local' License object with state (properties) filled by your WebService answer.
Otherwise i do not see why you would want to use a 'local' License object ?

You should not share the assembly between your web service and your client but instead create an instance of your License from your web service proxy types (should be found into service.x)

You need to create an instance from the webserviceproxy rather than from the asembly.
When you add a service reference to your webserice from the client it will generate proxy classes for you.Inside these you will have the License defined.use this to create an instance and pass it rather than referencing directly from your assembly.

Related

My class lost its methods during serialization

What's my Problem
Object returned from the ASMX service is used in Silverlight application. Class has methods but the result from the ASMX WebMethod does not show methods on the object.
Tell me more
here is my class
public class Dog
{
public string Name{get;set;}
public void Bark();
}
here is the WebMethod
[WebMethod]
public List<Dog> Findlabrador()
{
blah blah blah
return list_of_labrador;
}
the silverlight code
void LabradorFetchCompleted(object sender, LabradorFetchCompletedEventArgs e)
{
var list_of_labrador = e.Result;
foreach(var labradorDog in list_of_labrador)
{
labradorDog.Bark();
//** WTH my labrador can't BARK** Bark method is not shown in intellisense there is compilation error if i explicitly specify
}
}
I am a programmer not a layman
Ok hmm, let me put in your words. Here are steps for you to reproduce the issue
Create a Silverlight Application project ( Let VS create Website to host the application)
Create a Silverlight Class library create the Dog class inside it
Compile the Silverlight Class library to assembly(Dog.dll)
Add reference to Dog.dll silverlight assembly to the silverlight application project
Add a WebService application to the project ( DogService.asmx note the asmx extension)
Add a reference to the Silverlight Dog.dll assembly for the DogService
return hardcoded List<Dog> class from a WebMethod inside it
Add a reference from the Service to Silverlight application, create a instance of proxy client and invoke the method
Watch as your Dog too can't Bark :(
Methods are never serialized. Only data. Your methods, events, indexers, constructors, etc, will never be serialized.
You should not be using ASMX services anyway. Use WCF instead. WCF, among other things, gives you the ability to share datatypes between the client and service. This would allow something like "serializing methods": the same methods could be used both on the client and server.
You are supposed to define all common classes using portable class libraries, http://msdn.microsoft.com/en-us/library/gg597391.aspx
And then when consuming the web service within Silverlight, you should ask the proxy generator to reuse those classes. That makes sure you get all the functions.
Web service definition (WSDL) only takes care of fields/properties. Methods are not transferred over the wire.

Reporting Services Web Service, C# .NET code reuse

I'm building a custom front-end for a collection of reporting services servers. I'm adding the ReportingServices2005 web reference to my project using;
http://server/ReportServer_InstanceName/ReportService2005.asmx?wsdl
At the moment my approach is to add this reference for each server, however I'm then struggling with the code reuse aspect. The reporting services classes are then different namespaces.
I'd like to have a method as below;
public string ListReports(Server1WebService.ReportingService2005 service) {
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
service.Server1WebService.CatalogItem[] children = service.ListChildren("/", true);
string list = String.Empty;
foreach (Server1WebService.CatalogItem i in children) {
if (!i.Hidden)
list += i.Name + "</br>";
}
return list;
}
To make this method reusable I need to know how to refactor this so that any instance of the ReportingService2005 class can be passed regardless of the namespace. At the moment I have to specify Server1WebService for all references to ReportingService2005 and CatalogItem.
Provided that all of the SSRS instances are the same version, You should be able to set the URL property on the proxy object:
Server1WebService server.url = new uri ("http://server/ReportServer_InstanceName/ReportService2005.asmx?wsdl"));
If you have multiple versions to deal with, you may need to provide some type of factory object that can correctly instantiate the correct version.
Hope this helps

How to have a core class call a Client Class?

I am trying to build a core application that uses plugins so that the core never changes and each time we get a new client we write a module for them. We implement a interface called IClientPlugin with the new customer class.
This is using Compact Framework 3.5 and windows mobile 6.5.3.
So here is what I need to acheive:
this is a warehouse management system. The first task is to receive in the product from a truck scanning barcodes off packages with the handheld device.
The core module for this is started when the person clicks the receiving menu item.
the core method is - callClientMethod()
I know the client name and it is stored in a global variable at login and the class will be {clientname}.cs
and contain a method called processReceiving().
I know how to instantiate this object.
The question is: is there a way I can dynamically create a instance of the client class without hardcoding case statements?
For example suppose I have 2 clients Acme and Widgets. They each get a client class, namely Acme.cs and Widgets.cs
If I login as Acme or Widgets I want the code to dynamically create a instance of the Client class that I logged in as so that the core code does not have to change as I add more clients as long as I add a module for them.
psuedo example:
var myClient = New (Clientname)();
Is this possible or is there a better design approach or is the switch/case statement a neccessary evil?
You can use reflection to create objects dynamically.
There are many ways to load a type or assembly. Lets start with a simple one:
Type clientType = Type.GetType("AssemblyName, TypeName");
IClientPlugin clientPlugin =
(IClientPlugin)Activator.CreateInstance(clientType);
If your client is named myClient1 and you have the convention, that your assemblies are named for example like Clients.ClientName.dll then you can write a function:
IClientPlugin CreatePluginInstance(string clientName) {
string typeName = string.Format("Clients.{0}, {0}", clientName);
Type clientType = Type.GetType(typeName);
IClientPlugin clientPluginInstance =
(IClientPlugin)Activator.CreateInstance(clientType);
return clientPluginInstance;
}
EDIT
If your plugin classes are located in the same assembly as your main project, you can simplify the call of Type.GetType to just specify the classname:
Type.GetType(clientName);
var myClient = Activator.CreateComInstanceFrom("Acme.dll","Acme");
Where you can parametrize the Assembly name and the type name.

Unable to cast object of type MyObject to type MyObject

I have this scenario where a webservice method I'm consuming in C# returns a Business object, when calling the webservice method with the following code I get the exception "Unable to cast object of type ContactInfo to type ContactInfo" in the reference.cs class of the web reference
Code:
ContactInfo contactInfo = new ContactInfo();
Contact contact = new Contact();
contactInfo = contact.Load(this.ContactID.Value);
Any help would be much appreciated.
This is because one of the ContactInfo objects is a web service proxy, and is in a different namespace.
It's a known problem with asmx-style web services. In the past I've implemented automatic shallow-copy to work around it (here's how, although if I were doing it again I'd probably look at AutoMapper instead).
For example, if you have an assembly with the following class:
MyProject.ContactInfo
and you return an instance of it from a web method:
public class DoSomethingService : System.Web.Services.WebService
{
public MyProject.ContactInfo GetContactInfo(int id)
{
// Code here...
}
}
Then when you add the web reference to your client project, you actually get this:
MyClientProject.DoSomethingService.ContactInfo
This means that if, in your client application, you call the web service to get a ContactInfo, you have this situation:
namespace MyClientProject
{
public class MyClientClass
{
public void AskWebServiceForContactInfo()
{
using (var service = new DoSomethingService())
{
MyClientProject.DoSomethingService.ContactInfo contactInfo = service.GetContactInfo(1);
// ERROR: You can't cast this:
MyProject.ContactInfo localContactInfo = contactInfo;
}
}
}
}
It's on that last line that I use my ShallowCopy class:
namespace MyClientProject
{
public class MyClientClass
{
public void AskWebServiceForContactInfo()
{
using (var service = new DoSomethingService())
{
MyClientProject.DoSomethingService.ContactInfo contactInfo = service.GetContactInfo(1);
// We actually get a new object here, of the correct namespace
MyProject.ContactInfo localContactInfo = ShallowCopy.Copy<MyClientProject.DoSomethingService.ContactInfo, MyProject.ContactInfo>(contactInfo);
}
}
}
}
NOTE
This only works because the proxy class and the "real" class have exactly the same properties (one is generated from the other by Visual Studio).
As several of the other answers have suggested, it is because .NET sees them as two different classes. I personally would recommend using something like AutoMapper. I've been using it, and it seems pretty awesome. You can copy your objects in 1-2 lines of code.
Mapper.CreateMap<SourceClass, DestinationClass>();
destinationInstance = Mapper.Map<SourceClass, DestinationClass>(sourceInstance);
Actually this is not a bug. It's a problem with the version changes of your own project!
Because your final run don't use the original imported references on compile!
For example, I was making a chat server, client. I used a packet structure to transmit data on client project.
Then imported the same reference to server project.
When casting Packet packet = (Packet)binaryFormatter.Deserialize(stream); I got the same error. Because the actual running reference at server project is not the reference now at client project! Because I have rebuilt client project many times after!
In casting <new object>=(<new object>) <old object> always the new object needs to be a newer or same version as the old object!
So what I did was I built a separate project to create a DLL for the Packet class and imported the DLL file to both projects.
If I did any change to Packet class, I have to import the reference to both client and server again.
Then the casting won't give the above exception!
How are you referencing the class in your web service project as well as consumer project? If you have simply used a file link, this could well explain the cause of the error. The way serialiasation works for .NET (Web Services or otherwise I believe) is by using reflection to load/dump the data of an object. If the files are simply linked, then they are actually getting compiled to different types in different assemblies, which would explain why you have the same name but can't cast between them. I recommend creating a 'Core' library which both the web service and consumer project references, and contains the ContactInfo class which you use everywhere.
This isn't a problem - it's a feature.
They are two independent classes. Compare the two, and notice that the proxy class has none of the constructors, methods, indexers, or other behavior from the original class. This is exactly the same thing that would happen if you consumed the ASMX service with a Java program.
Seems like you have two different classes on both ends. Your application has ContactInfo class and your webservice also have the ContactInfo class. Both are two completely different classes. One way is to use the WebService class on your side. If you are using ContactInfo inside your web service then it will be serialized and will be available on the client side for use.
You can also modify your References.cs file generated by Visual Studio when the web reference is added. If you remove the proxy generated classes and add a reference (using statements) to your personal classes, you'll be able to use them straight away, without shallow copy / reflection or heavy mapping. (but you'll have to re-apply your modification if you regenerate the proxy layer).
I also tried to serialize the proxy object and deserialize them back in my DTO classes but it was quite heavy resources wise so I ended up modifying the References cs generated layer.
Hope it will help other people coming here :)
Kindly.

Webservice C# constructor does not allow arguments?

Im trying to create a web services that takes some arguments in its constructor to save round trips, but i keep getting the error:
CS1729 "servicename" does not contain a constructor that takes '1' arguments
although when I try to create an instant locally (in the same project as the service) everything works fine... what gives?
web service:
public class ayyash : System.Web.Services.WebService {
private string _myname;
public ayyash (string myname) {
_myname = myname;
//Uncomment the following line if using designed components
//InitializeComponent();
}
}
consumption:
ayyash a = new ayyash("my name is ayyash");
output:
Compiler Error Message: CS1729: 'ayyash' does not contain a constructor that takes '1' arguments
The server side constructor is not called when you instantiate your client proxy. It is called when the server side object is created; that is, if and when a web service method is called.
Also worth nothing is that you cannot have instance members on a web service. You cannot accept "name" in the constructior and use it from other methods; you must send in "name" into each web service method as an argument. In short, web service "state" must be passed to the service via method arguments or a cookie (though using the latter will cause you problems if you move to WCF).
Just imagine that everytime you call a method on your proxy object, a new server side object is created and that method is called before the object is destroyed. This is not strictly true (the object can be pooled), but it will help you design your web services.
When the client is "instantiating" your web service it is not calling the constructor on your service. It is instantiating a local proxy object that represents your service. The proxy object generated by .NET only supports a default constructor. This is why you get a compiler error.
The reason why the local object works is that you are not actually calling a web service. You are simply instantiating a local object and then calling a method on it.
I think you need to change your approach to pass in all of the data required to the WebMethod. The typical approach with web services is to have a stateless service that accepts all of the data required to perform the requested operation.
For example:
[WebMethod]
public string DoSomething(string name, string otherData)
{
ayyash yourObject = new ayyash(name);
return yourObject.DoIt(otherData);
}
The default constructor will be called when the service host creates an instance in request to a service request message.
Why not get the default constructor to get the data it needs? You could delegate to the parameterised constructor.
public MyWebService : this(xxx) {}
What I mean is that the service host will always create an instance of your class (to handle the request via the default constructor. If you want to pass parameters to it you have a number of options:
In the Default constructor go off the locate the data it needs
Pass the data in the Request
Possibly (I'm not sure) extend/modify the asp.net request response pipe line to use a different service instance creation mechanism. This link has some further examples.
I believe that WCF will allow you to do this easily more easily. Also you can use the HTTPListener directly.

Categories

Resources