Interfaces not properly represent in proxy objects - c#

Using many of the fine examples on this website, I have gotten my WCF service to properly serialize and deserialize concrete objects of interface types across the wire. Unfortunately, why seems to be lacking to me is client support.
A user has retrieved the meta-data from my service and is using that to auto-generate a service reference in visual studio 2012 with "add service reference". They are complaining that in their reference.cs (and thus in their auto-fill tool-tips), interfaces aren't coming across and are replaced by object.
For example, in my service interface code file:
[ServiceKnownType(typeof(ConcreteObject))]
...
[OperationContract]
bool WorkMethod(IMyInterface argument1);
...
but what they see is:
...
[OperationContract]
bool WorkMethod(object argument1);
...
As stated above, my client library works fine because I understand "object" really means "IMyInterface". But this is unclear to another client. How do you force the generated proxy objects to include interfaces, and properly represent the request type?
Thanks in advance!
Edit: Example interface, as per request.
public interface IMyInterface
{
bool DoWork(int i);
string SomeProperty { get; }
}
[DataContract]
[KnownType(typeof(IMyInterface))]
public class ConcreteObject : IMyInterface
{
//Working implementation here.
...
}

Related

Why do my WCF class names have the parent class as part of their name?

I've been experimenting with Silverlight-Enabled WCF services and I'm getting a strange behavior that doesn't happen in the tutorial I was using. I create a simple operation contract like such: (yes, I know there is no interface with everything defined, it's something that the Silverlight-enabled template does)
[ServiceContract(Namespace = "")]
[SilverlightFaultBehavior]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class TestService1
{
public class TestResponse
{
public string Hello { get; set; }
}
[OperationContract]
public TestResponse TestCall()
{
return new TestResponse();
}
}
Then I go and create a reference to it like I would a regular WCF service. But when I go to use my defined classes:
ServiceReference2.TestService1TestResponse test = new ServiceReference2.TestService1TestResponse();
Whereas I'm expecting ServiceReference2.TestResponse. Any idea why my parent class name is being concatenated onto the front of my datamember class names? I added a service reference to a plain console application and the same thing happens, so it's not a silverlight related thing.. maybe some setting in Silverlight-enabled WEC services? I watched this tutorial https://www.youtube.com/watch?v=8ln2LyWvf6Q to see if it happened for others, but it looks like the class names work fine there.
Out of luck I discovered what the issue was. I need to have the TestResponse class declared outside of the TestService1 class. I'm a little surprised the code generator for creating service references creates the classes in this way. I'd expect a ServiceReference2.TestService1.TestResponse instead, which is what threw me off so much.

WCF - Implementing a ServiceHostFactory to use into IIS context (svc file)

I've successfully implemented a self-hosted WCF service. For legacy matters, the host binding configuration is read from a non-standard source (instead of app.config). When porting this service to IIS, I run into the problem of loading the settings and I found that the solution would involve implementing a class inherited from ServiceHostFactory.
My problem, though, is that the CreateServiceHost method only receives the concrete type and the URI from the SVC file, but I wanted to re-use this class to further implementations and need more information: like the interface that defines the ServiceContract and the binding already configured.
I found this excellent article from #carlosfigueira, but its implementation uses the factory to return a host that is specific to the service, in a 1-to-1 relation. I sure can do it, but that will lead to several specific factories, with lots of copy-and-paste code and I'd ratter avoid it. Is it possible? If so, how can I do it?
There is no built-in way of finding out which contracts are implemented by a service class, but the code shouldn't be too hard. It's something along the lines of the function below. You'll need some logic to determine the relative address if you have multiple contract types (i.e., if you have a single contract, use "", if you have multiple, use the contract name as the address).
private IEnumerable<Type> GetContractType(Type serviceType)
{
if (HasServiceContract(serviceType))
{
yield return serviceType;
}
var contractInterfaceTypes = serviceType.GetInterfaces()
.Where(i => HasServiceContract(i));
foreach (var type in contractInterfaceTypes)
{
yield return type;
}
// if you want, you can also go to the service base class,
// interface inheritance, etc.
}
private static bool HasServiceContract(Type type)
{
return Attribute.IsDefined(type, typeof(ServiceContractAttribute), false);
}

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.

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.

how to use your same Domain entities throug a .Net webservice?

if you have an entity which is reference in the client and a webservice like this
public class Post
{
public int ID {get; set;}
string Data {get; set;}
}
public class MyService: System.Web.Services.WebService
{
[WebMethod]
public int Write (Post post)
{
//Do stuff
}
}
on the client in order to use the entity you to instantiate from the proxy class
public void ClientMethod()
{
var post = new proxyclass.Post();
//fill post
new ProxyClass.Myservice().Write(post)
}
how can i use my domain entity to call the webservice?
public void ClientMethod()
{
var post = new Post();
//fill post
new ProxyClass.Myservice().Write(post)
}
Basically, you can't - with regular web-services, at least... the proxy class is completely separate. However, the above is possible with WCF, where you don't actually need proxy classes at all (however, for SOA purity it is a good idea to use them).
You could use reflection (etc) to copy the properties between your domain entities and the proxies, but it is quite hard to get this 100% right (although xml serialization should work [in theory] as an intermediate language).
So; if you want to use assembly sharing; consider using WCF, which supports this ;-p
To get hold of a service without using a proxy layer, you can do tricks like:
public class WcfClient<T> : ClientBase<T> where T : class
{
public T Service { get { return base.Channel; } }
}
(this will access the default configuration from the app.config; for more control you need to add a few constructor overloads matching to the base constructor overloads)
Then:
interface IFoo {void Bar();}
...
using(WcfClient<IFoo> client = new WcfClient<IFoo>()) {
client.Service.Bar();
}
I suspect that one of these might answer your qestion. The common theme is wsdl.exe /sharetypes and svcutil /reference.
Managing 2 web references with shared class dependency in a .NET project
Force .NET webservice to use local object class, not proxy class
.Net Consuming Web Service: Identical types in two different services
How to get a webserice to serialize/deserialize the same type in .net
.NET SOAP Common types
wsdl.exe /sharetypes
You should use WCF for new development whenever possible.
However, you should reconsider your reasons for wanting to use your domain class on the client. It does violate the principles of SOA by exposing to the client some details of the implementation of the service. Why should the client know anything about your entity classes, beyond the data that they contain?
For instance, your entity classes may contain methods to save the entity to the database. Why does your client need access to that method?
Also, one of the principals of SOA is to interoperate with different platforms. As soon as you require your client to use your (.NET) entity, you prevent a Java or PHP client from being written to use your service.
You may have good enough reasons to overcome such objections, but I recommend that you think it through and make sure your reasons are good enough.
For cases like this you're better to use json for sending and receiving data to and from web service.
Newtonsoft.json is the best json serializer for .Net. so you should change your Write method like below:
public void ClientMethod()
{
var post = new Post();
//fill post
new ProxyClass.Myservice().Write(JsonConvert.SerializeObject(post))
}

Categories

Resources