Web Service proxy class to implement interface - c#

I am looking for a way to have the generated proxy class for a Web Reference (not WCF) implement a common interface in order to easily switch between web service access and "direct" access to our business layer in the client application, something like:
public IBusiness GetBusinessObject()
{
if (_mode = "remote")
return new BusinessWebService.Business(); // access through web service proxy class
else
return new Business(); // direct access
}
However, custom types (e.g. the CustomSerializableType in the examples below) aren't referenced in the generated proxy class. Instead new, identical types are generated, which makes it impossible for the proxy class to implement the interface.
Is there some way to make the generated proxy class reference these types, or am I going about this all wrong? Should I consider converting the web service to a WCF service instead?
Details
Our solution consists of these four projects:
A business library (contains business logic, accesses data store)
A common library (contains common functionality, including the CustomSerializableType)
A web service (acts as a proxy between remote clients and the business layer)
A windows application
Our client wants the windows application to be able to run in two different modes:
Local mode, where the application simply uses the business library directly to access data
Remote mode, where the application communicates with the web service to access data
In order to do this, we have created an interface, IBusiness, which is located in the common library and contains all business methods.
Interface
public interface IBusiness
{
CustomSerializableType DoSomeWork();
}
Business layer
public class Business : IBusiness
{
public CustomSerializableType DoSomeWork()
{
// access data store
}
}
Web service
public class WebServiceBusiness : IBusiness
{
private Business _business = new Business();
[WebMethod]
public CustomSerializableType DoSomeWork()
{
return _business.DoSomeWork();
}
}
Generated proxy class (a ton of code left out for readability)
public partial class Business
: System.Web.Services.Protocols.SoapHttpClientProtocol
{
public CustomSerializableType DoSomeWork()
{
// ...
}
public partial class CustomSerializableType {
// PROBLEM: this new type is referenced, instead of the
// type in the common library
}
}

Assuming that the default namespace for your client is "Client", and that your web reference is named "Proxy", then do the following;
In the root of your client project, create a folder named "Proxy".
In that folder, create a class named "Business".
Make that class public and partial, and have it implement your IBusiness interface
This way, you do not need to modify the Reference.cs. You should never modify Reference.cs, or any other file produced through code generation.
Note that this violates the principals of SOA by tightly binding your client to your service. At the very least, you should define those interfaces in a separate project, so that you are only sharing the "interface" project between the client and service.

Related

Using a client proxy with rest in C#

Running into a block trying to follow the logic of an example program. The example is used to demonstrate creating a contract, create a rest web service and then consume the rest service.
What throws me is I have the interface defined in the contract
namespace ProductDetailsContracts
{
[ServiceContract]
public interface IProductDetails
{
[OperationContract]
[WebGet(UriTemplate = "products/{productID}")]
Product GetProduct(string productID);
}
}
then used in the web service
using ProductDetailsContracts;
public class ProductDetails : IProductDetails
{
public Product GetProduct(string productID)
{
//do something
}
}
The code is then consumed in the client
using ProductDetailsContracts;
namespace ProductClient
{
class ProductClientProxy : ClientBase<IProductDetails>, IProductDetails
{
public Product GetProduct(string productID)
{
return this.Channel.GetProduct(productID);
}
}
}
I feel ClientBase<IProductDetails> is the key but I don't see how it is associated with the web service ProductDetails. My real goal to understanding this will be to run a client application that can add and update records in a SQL Server.
The interface you defined is the contract you pass to your client which tells them what services you provide, in your case you provide a GetProduct method.
Then, you create a concrete implementation of that contract, so when client code calls on your interface, they will end up invoking that concrete implementation, which will probably access some external resource (a database or a file) containing the product.
Your ProductClientProxy, which inherits from ClientBase<IProductDetails> is responsible for settings up the channel that will allow the client to make calls to your service. ClientBase is part of the WCF infrastructure, and is the class that actually reads the settings from your app.config and is responsible for settings up communication.
I suggest you read more about ClientBase and even look at the source code

How to force WebService reference to implement common interface?

I'm creating a study project using .net web services and I came across with this problem:
In order to provide for an opportunity to change the web server or even it's nature (it's the part of the task) I created an interface in a separate .dll that every possible (web)services must implement. Say,
public interface IDataAccess
{
// Group of methods which are used for login/logout
bool isUserRegistered(string username);
bool authorize(string username, string password);
//...
}
And I make the web service implement this interface:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Server : System.Web.Services.WebService, IDataAccess
{
//...
}
Then, in the client, I create a reference (namespace WebReference) to this service specifying to reuse type in all assemblies and try to do the following:
private IDataAccess webService = (IDataAccess)(new WebReference.Server());
but this assignment throws exception in runtime stating the convertion can't be done, and, indeed, in the Reference.cs (which is a part of what is created by adding reference to Web Service there is a redeclaration of Server class which doesn't declare IDataAccessImplementation:
public partial class Server : System.Web.Services.Protocols.SoapHttpClientProtocol {
//...
}
So, my question is how to make this reference implement that common interface IDataAccess without manually editting the file Reference.cs?
Firstly, you really don't need to implement the interface on the server side - that will do nothing for the generated code.
Next, note that the declaration is of a partial class. You can use that to your advantage.
All you need to do is create another C# file, which has:
public partial class Server : SoapHttpClientProtocol, IDataAccess {}
That's all you need (in the right namespace and with the right using directives). No code - that's all provided in the generated class. The C# compiler will blend the two declarations, and then you can just use:
private IDataAccess webService = new WebReference.Server();
... or better yet, inject it via a constructor so that you can write tests which don't need to use the real implementation at all!

WCF service generated by WSCF.blue Service Error "implementation type is an interface or abstract class and no implementation object was provided"

I am using C# Visual Studio 2012 to create a wcf service.
I had the WSCF.blue tool generate the wsdl from the xsd-s. Then I generated the web service code using the same tool. WSCF.blue does not create a Service Contract and a Data Contract. It creates an interface and a .svc file that contains a class that implements the interface.
When generating the web service code I selected the option to create the abstract classes because I want to be able to keep the implementation of these classes in a separate file.
The abstract class looks like this:
[KnownType(typeof(WebMobileImplementation))]
public abstract class WebMobile : IWebMobile
{
public abstract PutLocationsResponse PutLocations(PutLocationsRequest request);
}
The implementing class (in a different file) looks like this (for now):
public class WebMobileImplementation : WebMobile
{
public override PutLocationsResponse PutLocations(PutLocationsRequest request)
{
PutLocationsResponse response = new PutLocationsResponse();
return response;
}
}
When trying to browse the service I get the message: "Service implementation type is an interface or abstract class and no implementation object was provided"
I thought that adding the knowntype to the implementing class will do the trick but it seems that the implementation is not 'seen' when running the service. What else can I do to 'connect' them?
In WCF 4.0, you can define virtual service activation endpoints that map to your service types in Web.config. This makes it possible to activate WCF services without having to maintain physical .svc files.
<serviceHostingEnvironment>
<serviceActivations>
<add relativeAddress="WebMobile.svc"
service="WebMobileNamespace.WebMobileImplementation"/>
</serviceActivations>
</serviceHostingEnvironment>

Transport classes by WCF

My goal is to load an external class in a running application environment (like a plugin model). Creating an instances of the class in an running environment is not the problem (the classes using an Interface). The problem is to get the class which must be available from a central WCF services.
Is it possible to transport an class or assembly to the client by using WCF?
Something like this:
[ServiceContract]
public interface ISourceData
{
[OperationContract]
xxx GetClassData { get; set; } // <-- here to get data the class to app can create an instances of this
}
I hope that you understand my situation. Thanks.
First of all, the attribute in your sample above must be OperationContract, not DataContract. The DataContract attribute is for the class that you want to return in GetClassData.
The problem in your situation is that on the client side the class itself is not replicated when you add the service reference, but a stub is generated for the properties that you define in your DataContract. So you get the data, but not the logic.
You could now create an assembly which defines the data classes to be exchanged and add them to both the service and the client, but as I understand your question, you want to dynamically load assemblies in the service and send these "implementations" to the client without the client actually having access to the DLL that implements the class. This may not be possible in an easy way.
EDIT
Re-reading your question I now understand that you do not want to "transfer an instance", but you want to transfer the class definition. One way would be to actually transfer the source code for the class and try to use Reflection.Emit to create a dynamic assembly. A sample of this can be found here.
Yes , you can .
and also you must to define the type of your class like ↓
[ServiceKnownType(typeof(xxx))]
public interface IService
I think you need the assembly on the client so you need to transfer the dll containing the assembly to the client, then have the client save it in a plugins directory for the app and have the app and load it from there.
Although I image that this is going to be a permissions nightmare to get the app to be able to use the dlls downloaded from the service.
You would mark up the classes used in your interface like this:
[ServiceContract]
public interface ISourceData
{
[OperationContract]
MyClass GetClassData();
}
[DataContract]
public class MyClass
{
[DataMember]
public string MyMember1 {get; set;} // included in transport
public int MyMember2 {get; set;} // not included
}

Class constructor (from C# web service) won't auto-implement properties in C# MVC

I'm running two instances of VS2010 on my local machine. One instance is running my Web Service (written in C#). The other instance is running my MVC web app (also C#). The MVC web app has a reference to the web service. I can successfully invoke web service methods from within the MVC app.
In my web service is a PageNavigation class:
// PageNavigation.cs
using System;
using System.Collections.Generic;
using System.Text;
public class PageNavigation
{
public string Page_Number { get; set; }
public string Page_Count { get; set; }
public PageNavigation()
{
Page_Number = "1";
Page_Count = "2";
}
}
By default, this should return an object with auto-implemented properties when I call the class constructor:
WebService.PageNavigation pageNavigation = new WebService.PageNavigation();
This works when constructing a PageNavigation object elsewhere in the web service.
pageNavigation.Page_Number
"1"
pageNavigation.Page_Count
"2"
However, running the same line of code on the MVC isn't giving the same result; the object's properties are all null values.
pageNavigation.Page_Number
null
pageNavigation.Page_Count
null
Is this the expected behavior? Is there a way to populate the properties with default values as intended? If more information is needed please let me know and I will update the question.
The service reference only sees the schema of your object, not business logic; in your case, your service reference just created a shell data type in the MVC application. When you create a service reference, it's actually creating another type with the same property names and types as the type defined in the service.
For your particular scenario (simply providing default property values and not more general business logic), you should be able to apply the [System.ComponentModel.DefaultValue] attribute to your properties in order for the class generator to recognize that these properties should be populated with a default value.
Incidentally, if the service reference were reusing existing types (if you had this type in a common library that was referenced both by the service and the application, for example), then your business logic would be intact.
An alternative would be to implement a factory pattern, whereby you call a function on the web service that instantiates (and optionally populates) the data object, then returns it to the client.
Yes, this is expected behaviour. The MVC site is not actually using your PageNavigation class. It is a simple copy (generated when you add the web service reference) containing of all the properties, but none of the methods, including the constructor.
You could work around this by refactoring your service so the entities are in a separate assembly and then you can reuse this assembly on the client as an option when you generate the proxy.
If you insist on using the same types between client and service, then on the "Advanced" tab of the "Add Service Reference" dialog, you can choose to reuse the types in your server assembly.
I would move that class out of the service and into a class library project referenced by the service and by the client.
And I wouldn't do this for such a small reason as default values. this violates SOA by coupling the service and the client. It will obviously not work for clients which are not running .NET.
What serializer are you using to deserialize the response from the server? Some of them (like the DataContractSerializer for example) do not call the default constructor.
The solution that you should use if you are in fact using DataContractSerializer is to use the OnDeserialized attribute like this:
using System.Runtime.Serialization;
public class PageNavigation
{
public string Page_Number { get; set; }
public string Page_Count { get; set; }
public PageNavigation()
{
Init();
}
[OnDeserialize]
void Init()
{
Page_Number = "1";
Page_Count = "2";
}
}

Categories