Proxy for interacting with WCF services on client - c#

Please, Help me !
I've some problems with my project (WPF with WCF).
My project its client-server interaction. In server I've EF that interaction with PatternRepository . On server it`s a wcf interaction I have services.
Each service its repository. In each service I have a set of commands for communication between server and client . Between client and server data transfer occurs via Json . Example, it's service:
public class ProductRepositoryService : IProductRepositoryService
{
public void AddProduct(string json)
{
_productRepository.Add(wrapperProduct.DeserializeProduct(json));
_productRepository.Save();
}
public void DeleteProduct(string json)
{ productRepository.Delete(_productRepository.GetById(wrapperProduct.DeserializeProduct(json).Id));
_productRepository.Save();
}
}
Example, its ProductSeviceLogics that interaction with ProductService :
ProductRepositoryServiceClient _service1Client;
public ProductSeviceLogics()
{
this._service1Client = new ProductRepositoryServiceClient();
}
public void AddProduct(string json)
{
_service1Client.AddProduct(json);
}
public void DeleteProduct(string json)
{
_service1Client.DeleteProduct(json);
}
It's mean that if I'll create services. I'll be create those methods for each service on the server and the client. I think that it's very bad .
So my question, How can i do so that these methods will be for all services ?
That is, I want not to create this methods for each service and for each client.

I recommend you to have a look into this ASP.NET MVC Solution Architecture article. Download the code and have a look into that, how they maintain the Repositories/Services/Models in separate class library and make use in User interface or WCF or WebAPI.
Here I will provide some sample solution pattern.
Create a new blank solution : File -> New Project -> Other Project Type -> Blank Solution and name it as MyProject.
Create new class library listed below
MyProject.Model
Create POCO class like Product, Sale
MyProject.Data
Add a reference of Model.
Contains EF(DbSet and DbContext) and Repositories like ProductRepository, SalesRepository.
MyProject.Service
Add reference Model and Data.
Make a call to your repositories from this project.
Create User Interface and WCF services
MyProject.Web
MyProject.WCF
Add a reference of Model and Service.
Your work flow like this WCF or Web Calls --> Service --> Repositories --> EF, So you can avoid creating multiple service for client and server.
Hope this helps you.

I solved this issue.
Generate proxy for WCF Service
Generate Proxy by implementing ClientBase class*
Generating proxy by using ClientBase class option has an advantage that it creates proxy at run time, so it will accommodate service implementation changes. Let’s follow the steps to generate proxy.
Add a Client Project to solution named as “ClientApp2″ that is
basically a Console Application.
enter image description here
Add reference of StudentService Project to ClientApp2. Add following
proxy class using ClientBase as:
public class StudentServiceProxy : ClientBase<IStudentService>, IStudentService
{
public string GetStudentInfo(int studentId)
{
return base.Channel.GetStudentInfo(studentId);
}
}
Note: Don’t forget to add “using StudentService” to class.
Following is the code for program.cs class in ClientApp2. We are using above created proxy class to communicate with WCF Service
“StudentService“.
class Program
{
static void Main(string[] args)
{
StudentServiceProxy myclient;
myclient = new StudentServiceProxy();
int studentId = 1;
Console.WriteLine(“Calling StudentService with StudentId =1…..”);
Console.WriteLine(“Student Name = {0}”, myclient.GetStudentInfo(studentId));
Console.ReadLine();
}
}
Note: Don’t forget to add “using System.ServiceModel” to class.
App.Config file will have following configuration:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name=”WSHttpBinding_IStudentService” />
</wsHttpBinding>
</bindings>
<client>
<endpoint address=”http://localhost:4321/StudentService”
binding=”wsHttpBinding”
bindingConfiguration=”WSHttpBinding_IStudentService”
contract=”StudentService.IStudentService”
name=”WSHttpBinding_IStudentService”>
</endpoint>
</client>
Now, when we run the client application, we will receive the following same output as we get in earlier option “Adding Service Reference”.

Related

load WCF service by environment in .net core project

I have a problem while adding WCF in the .NET core project.
When I used .net in the past I can add multiple environments in web.config so I can load the correct web service at runtime (Dev, Rec, Prod).
The problem in the .net core project when I added a reference of my WCF service as Connected Service it created one file ConnectedService.json that contains a URL for the WCF service.
{
"ProviderId": "Microsoft.VisualStudio.ConnectedService.Wcf",
"Version": "15.0.20406.879",
"GettingStartedDocument": {
"Uri": "https://go.microsoft.com/fwlink/?linkid=858517"
},
"ExtendedData": {
"Uri": "*****?singleWsdl",
"Namespace": "Transverse.TokenService",
"SelectedAccessLevelForGeneratedClass": "Public",
"GenerateMessageContract": false,
"ReuseTypesinReferencedAssemblies": true,
"ReuseTypesinAllReferencedAssemblies": true,
"CollectionTypeReference": {
"Item1": "System.Collections.Generic.List`1",
"Item2": "System.Collections.dll"
},
"DictionaryCollectionTypeReference": {
"Item1": "System.Collections.Generic.Dictionary`2",
"Item2": "System.Collections.dll"
},
"CheckedReferencedAssemblies": [],
"InstanceId": null,
"Name": "Transverse.TokenService",
"Metadata": {}
}
}
My question how can I load the correct service based on the used environment.
Note.
In my Project, I did not have an appsettings neither web config. It is a .net core class library and it is called in ASP.NET core Application as Middleware.
As I understand from this article, this is Microsoft's recommendation:
Add new class file
Add same Namespace of service reference.cs
Add Partial Class to expand reference service class (declared in Reference.cs)
And Partial Method to implement ConfigureEndpoint() (declared in Reference.cs)
Implement ConfigureEndpoint() Method by Setting a new value for Endpoint
Example:
namespace Your_Reference_Service_Namespace
{
public partial class Your_Reference_Service_Client
{
static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials)
{
serviceEndpoint.Address =
new System.ServiceModel.EndpointAddress(new System.Uri("http://your_web_service_address"),
new System.ServiceModel.DnsEndpointIdentity(""));
}
}
}
Here, you can take the value from the appsettings.json file
new System.Uri(configuration.GetValue("yourServiceAddress")
For whom are interested by the solution
I added an endpoint for my service in each appseetings.{environment}.json and in Service class I inject new Instance of my service based on the environment variable ASPNETCORE_ENVIRONMENT
services.AddTransient<Transverse.TokenService.ITokenService>(provider =>
{
var client = new Transverse.TokenService.TokenServiceClient();
client.Endpoint.Address = new System.ServiceModel.EndpointAddress(Configuration["Services:TokenService"]);
return client;
});
Maybe is not the best but it works fine.
I am using .Net Core 3.1, this is my way when I call WCF Service.
var sUserClientRemoteAddress = _configuration.GetValue<string>("WCFRemoteAddress:UserClient");
UserClient userService = new UserClient(UserClient.EndpointConfiguration.CustomBinding_IUser, sUserClientRemoteAddress);
First, Get the endpoint remote address from appsettings.json
Second, Call web service client using that address in CTOR WCF Client Class parameter
Thanks in advance.
Use a ChannelFactory to consume your service.
WCF ChannelFactory vs generating proxy
A ChannelFactory allows you to set an EndpointAddress.
How to: Use the ChannelFactory
The URL for the endpoint can be loaded from a configuration file. In a more advanced setup a directory lookup for the service can be performed to retrieve the URL for the environment where the application is deployed. https://en.wikipedia.org/wiki/Service_provider_interface
https://github.com/jolmari/netcore-wcf-service-proxy
Example of consuming multiple WCF services using a proxy
implementation in a ASP.NET Core Web-application.
I just went with the simple route. Note: I'm on .NET 6.
Step 1:
Add the service reference by following steps in the MSFT guide:
https://learn.microsoft.com/en-us/dotnet/core/additional-tools/wcf-web-service-reference-guide
Step 2:
Create a factory to create WCF service client. You can pass the wcfUriBasedOnEnvironment from the main project or anywhere you want.
public static class WCFServicesClientFactory
{
// APIWCFServicesClient is the service client inside Reference.cs generated in Step 1
public static APIWCFServicesClient CreateUsingUri(string wcfUriBasedOnEnvironment)
{
return new APIWCFServicesClient(APIWCFServicesClient.EndpointConfiguration.BasicHttpBinding_IAPIWCFServices,
new System.ServiceModel.EndpointAddress(new System.Uri(wcfUriBasedOnEnvironment)));
}
}
Step 3:
Use it like:
var wcfClient = WCFServicesClientFactory.CreateUsingUri("http://your_web_service_address");

Web services and client DLL

I have a web service and a client DLL. The web service uses an Oracle database.
For testing the client DLL, I copied the web service and made it point to a test database. Then I copied the client DLL and added this test web service using "Add web reference".
What I would like to do is to use one web service and one client DLL but be able to tell the client DLL to use either use the test or production database rather than two identical web serivces and client DLLs.
Edit
I mis-stated the issue. What I need to do is use one client DLL and two web services (one production version, one development/test version) and be able to, somehow, tell the client DLL which web services to use.
This is a sample of how the web service, client DLL and client app are used:
public class DSSService : System.Web.Services.WebService
{
public DSSService()
{
}
[WebMethod(MessageName = "GetFacility", BufferResponse=true, Description = "blah.")]
public Facility GetFacility(string sFDBID, string sZip, string sFinNo)
{
Facility oFacility = ...;
...
return oFacility;
}
....
}
Client DLL:
namespace DSSConfig
{
string sWSURL;
public class Config
{
public Config()
{
}
public void SetWSURL(string sURL)
{
sWSURL = sURL;
}
public Facility GetFacility(string sFDBID, string sZip, string sFinNo)
{
DSSService Proxy = new DSSService();
proxy.Url = sWSURL;
Facility oFacility = Proxy.GetFacility(sFDBID, sZip, sFinNo);
return oFacility;
}
In client application, having DSSConfig DLL as reference:
DSSConfig oConfig = new DSSConfig();
oConfig.SetWSURL("http://myserver/WebService1/service.asmx");
oConfig.GetFacility("blah", "blah", "blah");
What you need to do is change the WEB Service to take a parameter that it will use to construct the connection string to the DB.
Then change client DLL to pass that parameter as part of the call or connection.
Then you can configure the Client DLL to using any technique you like to pass the parameter. My suggestion is perhaps derive a class from the generated proxy in the client DLL and use this in the client code.
Without specific implementation details I can't be more precise.

IIS hosting for WCF service with 2 contracts or hosting 2 services with dependencies

I'm developing a WCF service that has a contract called MyApp.IOperationService.
<service name="MyApp.OperationService">
<endpoint address="OperationService" binding="basicHttpBinding" contract="MyApp.IOperationService" />
</service>
For the service behaviour I used InstanceContextMode = InstanceContextMode.Single and ConcurrencyMode = ConcurrencyMode.Multiple because the application uses a shared physical resource.
I needed an administrative interface for this service and first I added a new contract within the same service. This approach didn't appeal to me because the administrative contract was exposed, through the metadata, to the clients using the operation contract.
Then I opted for creating another service altogether.
<service name="MyApp.AdminService">
<endpoint address="Admin" binding="netTcpBinding" contract="MyApp.IAdminService" />
</service>
This service has one operation, called Login, that propagates the pincode to the OperationService object.
namespace MyApp
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single, UseSynchronizationContext = false)]
public class AdminService : IAdmin
{
MyApp.OperationService objOperationService = null;
public AdminService(MyApp.OperationService objOperationService)
{
m_objOperationService = objOperationService;
}
public void Login(string pincode)
{
m_objOperationService.Login(pincode);
}
}
}
In a self-hosting environment I create a MyApp.OperationService object, then pass this object to the constructor of MyApp.AdminService. For IIS hosting, I discovered that I need to use WCF extensibility points and implement an IInstanceProvider, then use a ServiceHostFactory.
At this point I stopped and wondered if this will work at all, given that my AdminService expects an already created MyApp.OperationService that IIS controls, and it already seems awfully complicated for my humble purpose.
The question is if this (administrative contract/interface for an existing service that is not exposed through the metadata) can be achieved in another way?
Thank you.
I couldn't find a way to solve the problem, except using WCF extensibility points. I used Microsoft.Practices.Unity to manage the services through IoC, then used the Factory property in the .svc file.

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.

How to add SoapExtension attribute to generated web service client proxy without modifying the generated class?

I have created a SoapExtension class to capture the soap request and response from specific web service calls. In order to put this SoapExtension into effect, I have to add an attribute to the method in the generated proxy client.
For example, I've added the AuditSoapCapture attribute to this method:
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://blahblah.com/webservices/AddressSearch", RequestNamespace = "http://blahblah.com/webservices/", ResponseNamespace = "http://blahblah.com/webservices/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[blahblah.TriadLite.Core.AuditSoapCapture]
public System.Data.DataSet AddressSearch(string HouseNumber, string StreetName, string ZipCode) {
object[] results = this.Invoke("AddressSearch", new object[] {
HouseNumber,
StreetName,
ZipCode});
return ((System.Data.DataSet)(results[0]));
}
I am looking for a way to add this attribute to specific methods without modifying the generated client proxy, as they will get lost when we regenerate. Can I do this in a another partial class or interface or some other way?
Thanks!
Unfortunately, you'll need to modify the proxy code. The other possibilities you mention will not work - a parial class will not overwrite existing functionality, and there is no way that I'm aware of getting an interface to do what you need (compounded by the fact that there is no way to even let the proxy generator know that you intend to implement an interface).
Something that I've done in the past, in a situation where you have access to the source of the webservice, is to write a little app that will parse the code (as text) in the .asmx.cs file of the webservice to extract the names of all the methods that are tagged with [WebMethod]. Then the app "fixes up" the References.cs by inserting appropriate attributes onto the proxied methods, based on some settings file or somesuch. This works well because the naming conventions in the proxy map very neatly to the method names in the original service.
I may just end up injecting my SoapExtension by putting it into the Web.config. This will cause it to be run on every WS call without a client proxy method attribute. Then, I will modify the SoapExtension to look up the called WS method name on a list, and if it is on the list, then do the rest of the SoapExtension logic. I figure the hit on the list in this small volume application isn't going to kill performance.
6 years ago this was posted... So not sure if this will help anyone at this point.
I ran into something similar with a call to an old SOAP web service that had a dynamically generated proxy class that we didn't want to modify as it was auto-generated from the wsdl by the project. In order to solve this problem here is what we did.
The proxy class generated by wsdl.exe is a partial class. We extended this class like so to add a property with the information we wanted to access in the soapextension. You can add as many properties as you want...
partial class mysoapwebservice
{
public string myproperty{ get; set; }
}
in the web.config we registered the soap extension globaly on the project
<webServices>
<soapExtensionTypes>
<add type="MySoapExtension" priority="1" group="Low"/>
</soapExtensionTypes>
</webServices>
In the code were we created the web service object 'mysoapwebservice' we set the value of the property we needed.
In the soapextension you can get a reference to the web service that was called as well as the values. You can also determine the method call.
`
public class MySoapExtension: SoapExtension
{
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
{
// web service client object
var webserviceobject= ((SoapClientMessage)message).Client;
// method from web service that was called
var calledMethod = (SoapClientMessage)message).MethodInfo;
// checked the client type of webserviceobject and
//added method / property specific logic here
}
}
}
// other soap extension code
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class CriptoExtensionAttribute : SoapExtensionAttribute
[CriptoExtension]
public partial class MainService{

Categories

Resources