Hosting a WCF Service In A WinForm [duplicate] - c#

This question already has answers here:
Hosting WCF service inside a Windows Forms application
(3 answers)
Closed 7 years ago.
I am quite new to WCF. How do you host a WCF service in a WinForm? Obviously the service would only be available while the form is open but this is exactly what I am after.
There are only a few (poor) examples of doing it which I have found and even the MSDN starts talking about hosting one in a WinForm but then goes and implements it in a Windows Service.

You can open your app, and place something like this in your form:
Create your WCF interface
<ServiceContract()>
Public Interface IyourInterface
<OperationContract()>
Function asyouwant ....
Create the class that implements it
Public Class clsYourClass
Implements IyourInterface
Instantiate it from your winforms app.
(This is vb.net)
Dim oYourService As ServiceHost
Dim oYourBinding As New System.ServiceModel.BasicHttpBinding
' Or WSHttpBinding ... configure as you want
Dim aAddress As Uri()
aAddress= New Uri() {New Uri("http://localhost:port")}
oYourService = New ServiceHost(GetType(clsYourClass), aAddress)
oYourService.AddServiceEndpoint(GetType(IyourInterface), oYourBinding, "myWinformService.svc")
oYourService.Open()
4 - Try this: http://localhost:port/myWinformService.svc

Simple service for example..
IService
[ServiceContract]
public interface IService
{
[OperationContract]
string Calculate(int price, int Qty);
}
Service
public class Service : IService
{
public string Calculate(int price, int Qty)
{
return Convert.ToString(price * Qty);
}
}
Consume service by user
Go to Add Service reference option and discover the service. Add the service. Now the service displays in solution explorer.
http://localhost/WCFServiceSample/Service.svc
To check in web browser.
Usage in Application
using WindowsFormsApplicationWCF.ServiceReference1;
Service1Client obj = new Service1Client();
private void btnSubmit_Click(object sender, EventArgs e)
{
string result;
result = obj.Calculate(Convert.ToInt32(txtPrice.Text), Convert.ToInt32(txtQty.Text));
lblresult.Text = "The total price is" + result;
}
Check these links for you reference,
Hosting WCF service inside a Windows Forms application
http://www.c-sharpcorner.com/UploadFile/0c1bb2/consuming-wcf-service-in-windows-application/
https://msdn.microsoft.com/en-us/library/ms731758(v=vs.110).aspx

Related

Dynamically using same method in multiple web service references?

In c# .Net Framework 4.5 (Visual Studio Ultimate 2012, Version 11.0.61219.00 Update 5), I'm trying to define a service variable at runtime for which webservice to use. Each webservice (there are many) are all defined the same except for the endpoint url but the credentials will not cross over to authenticate. The below condition is menial to simplify the issue at hand. The following code gives the error: Cannot implicitly convert type WebService2.Service to WebService1.Service.
What I've tried: calling functions to return the proper service but the parameters or assignment all require a specific type.
var service = new WebService1.Service();
service = new WebService2.Service();
I want to be able to use the variable service in the rest of the program without having to duplicate code everywhere for using the many web service references.
It seems like what you are looking to do, you would need a common interface between the two services so you could inject whichever service you wish to use.
public class WebService1 : IWebService {...service code}
public class WebService2 : IWebService{...service code}
public interface IWebService{...service methods you will be calling}
Then you could do the following.
IWebService service = new WebService1.Service();
service = new WebService2.Service();
Assuming that the different services share the same method names, you can create an interface that all of the services implement by using the interface
IMyService.cs
interface IMyService
{
void MyMethod(string filter);
}
MyWebServiceImplementation.cs
public class MyWebServiceImplementation : IMyService
{
public void MyMethod(string filter);
}
MySecondWebServiceImplementation.cs
public class MySecondWebServiceImplementation : IMyService
{
public void MyMethod(string filter);
}
MyImplemetationCode.cs
//Use different services from same variable
IMyService service = new MyWebServiceImplementation();
service.MyMethod("filter");
service = new MySecondWebServiceImplementation();
service.MyMethod("another filter");

Passing an object list from a wcf service to an asp.net web application

I communicate between a windows service and an asp.net web application through a WCF service. For example: I pass data from the windows service to the wcf service and then to the web application. Works with strings, ints, and longs but I can't pass a list of objects.
Is there a proper way of doing that?
asp.net web application
Action
WcfService.ServiceClient1 client = new WcfService.ServiceClient1("BasicHttpBinding_IService1");
ViewBag.s = client.GetDiretorySize("something").ToString();
Wcf Service
IService1
[OperationContract]
List<Objects> GetDirectorySize(string path);
Service1
public List<Objects> GetDirectorySize(string path)
{
List<Objects> size = dh.GetSize(path);
return size;
}
Make sure that the classes you're passing around are defined in the WCF service's interface (default IService1.cs). Also make sure that the class is defined as an DataContract and DataMember
For example
[DataContract]
class MyClass
{
[DataMember]
string MyString { get; set;}
}
It's not clear from your question whether you've tried this but give this a go:
[OperationContract]
List<object> GetDirectorySize(string path);
Then change the method to:
public List<object> GetDirectorySize(string path)
{
List<object> MyList = new List<object>();
//Add items to your list...
return MyList;
}

WCF services consuming

I have two projects, one is a set of WCF services (let's call P1) and the other is a standard web application (P2).
As a start, we have consumed P1 services in P2 as SOAP services and everything went fine. Later we noticed that in all of our project deployments, we are hosting both P1 & P2 on the same server. So we thought why should we keep it like this - meaning: Why should we serialize/de-serialize the request/response every time for every method when it is running in the same server. So we made a decision to use P1 as standard project library reference in P2.
We had to make a lot of modifications because the proxy class name changes and having to remove the client "close" method after each call. Now, we have a new deployment that will requires P1 to be on a different server than P2, which we can change, and we have to consume P1 again as WCF service - meaning tons of changes all over the P2 and ending by having the serialization overhead on all of other deployments!
The question is, is there any way to make such a dynamic reference to P1, so no coding is required regardless the deployment is on 1 or 2 servers?
It is possible to make a WCF service run local( project reference ) or as a service based on some key on the web.config. I did the following example but I didnt test it but I have done exactly similar thing before
Add key in the web config say serviceMode="local/service"
Then say you have wcf service interface
[ServiceContract]
public class ICalculator
{
[OperationContract]
int Add(int x, int y);
}
implementation
public class Calculator
{
public int Add(int x, y)
{
return x+y;
}
}
///Now in your web application
you will have
public LocalProxy:ICalculator //this will use direct instance of the Calculator Service
{
private ICalculator _calculator
public LocalProxy(ICalculator calculator)
{
_calculator =calculator;
}
public int Add(int x, int y)
{
return _calculator.Add(x,y);
}
}
public class RemoteProxy:ICalculator ///This will be real wcf proxy
{
public int Add (int x,int y)
{
var endpointAddress = new EndpointAddress(EndpointUrl);
ChannelFactory<ICalculator> factory = null;
ICalculator calculator ;
try
{
// Just picking a simple binding here to focus on other aspects
Binding binding = new BasicHttpBinding();
factory = new ChannelFactory<ICalculator>(binding);
calculator= factory.CreateChannel(endpointAddress);
if (calculator== null)
{
throw new CommunicationException(
String.Format("Unable to connect to service at {0}", endpointUrl));
}
int sum= calculator.Add(x,y);
((IClientChannel)calculator).Close();
calculator = null;
factory.Close();
factory = null;
return sum;
}
finally
{
if (calculator!= null) ((IClientChannel)calculator).Close();
if (factory != null) factory.Abort();
}
}
}
Now how you use it
ICalculator _calculatorProxy;
//get the web config key here, you may use strategy pattern to select between the two proxies
if(key=="local)
{
_calculator= new LocalProxy(new Calculator)
}
else
{
_calculator= new RemoteProxy();
}
//then
_calculator.Add(3,5);
Note: Define your interfaces and data contracts in a separate assembly so that you can share it with the web application that needs wcf run as a service.
All your components in P2 which consume services from P1 should only consume the service interface (i.e. IMyService, ISomeOtherService). They should not care whether it is a local instance or a proxy and neither should they close the connection.
The easiest (imho) to realize this is by using dependency injection through an IoC like Castle Windsor (it's the only one I'm vaguely familiar with but there are several others out there). The container will be responsible to provide instances of the service interfaces. You can provide different implementations and configure the container at runtime with the appropriate one (WCF service or local instance). The container will also be responsible for disposing of the service components once they are not required anymore (i.e. calling Close() on the WCF proxies and doing nothing for the others).
It's a big topic so I'd suggest you search the internet for some of the keywords - there is lot of material out there.

WCF: Accessing the service instance from the server

Context:
I need to develop a monitoring server that monitors some of our applications (these applications are in c#). So I decided to develop the system with WCF which seems suitable for my needs.
These applications must register themselves to the monitoring server when they start. After that the monitoring server can call the methods Start or Stop of these applications.
Everything is completely executed on the same machine, nothing needs to be executed remotely.
So I developed a good prototype and everything works fine. Each application registers itself to the monitoring server.
Question:
ApplicationRegistrationService (see the code below) is the implementation of the monitoring service and it is a singleton instance due to the ServiceBehavior attribute.
Here my problem: I want to access the content of ApplicationRegistrationService per example, the number of connected applications from my server (ConsoleMonitoringServer in the example). But, I am not sure how to achieve this.
Do I need to create a channel in my server to the service like I did in my clients (ConsoleClient) or it exists a better way to achieve this?
Code:
The code is very simplified for the purpose of this question:
//The callback contract interface
public interface IApplicationAction
{
[OperationContract(IsOneWay = true)]
void Stop();
[OperationContract(IsOneWay = true)]
void Start();
}
[ServiceContract(SessionMode = SessionMode.Required,
CallbackContract = typeof(IApplicationAction))]
public interface IApplicationRegistration
{
[OperationContract]
void Register(Guid guid, string name);
[OperationContract]
void Unregister(Guid guid);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ApplicationRegistrationService : IApplicationRegistration
{
//IApplicationRegistration Implementation
}
public class ApplicationAction : IApplicationAction
{
//IApplicationAction Implementation
}
Console application for this example
class ConsoleClient
{
static void Main(string[] args)
{
ApplicationAction actions = new ApplicationAction();
DuplexChannelFactory<IApplicationRegistration> appRegPipeFactory =
new DuplexChannelFactory<IApplicationRegistration>(actions,
new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/AppReg"));
IApplicationRegistration proxy = appRegPipeFactory.CreateChannel();
proxy.Register(Guid.Empty, "ThisClientName");
//Do stuffs
}
}
Console server for this example
class ConsoleMonitoringServer
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(ApplicationRegistrationService),
new Uri[]{ new Uri("net.pipe://localhost")}))
{
host.AddServiceEndpoint(typeof(IApplicationRegistration),
new NetNamedPipeBinding(), "AppReg");
host.Open();
//Wait until some write something in the console
Console.ReadLine();
host.Close();
}
}
}
Finally, I find the answer and it was pretty easy. I just need to create the service instance and pass the reference to the constructor of ServiceHost.
So I need to replace the following code:
using (ServiceHost host = new ServiceHost(typeof(ApplicationRegistrationService),
new Uri[]{ new Uri("net.pipe://localhost")}))
by :
ApplicationRegistrationService myService = new ApplicationRegistrationService();
using (ServiceHost host = new ServiceHost(myService,
new Uri[]{ new Uri("net.pipe://localhost")}))
If you mean you'd like two way communication between your monitoring service and your registered services or nodes, then you probably should be using two way communication in WCF also known as duplex communication. Very cool stuff.
http://www.codeproject.com/KB/WCF/WCF_Duplex_UI_Threads.aspx

WCF consumed as WebService adds a boolean parameter?

I've created the default WCF Service in VS2008. It's called "Service1"
public class Service1 : IService1
{
public string GetData( int value )
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract( CompositeType composite )
{
if ( composite.BoolValue )
{
composite.StringValue += "Suffix";
}
return composite;
}
}
It works fine, the interface is IService1:
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData( int value );
[OperationContract]
CompositeType GetDataUsingDataContract( CompositeType composite );
// TODO: Add your service operations here
}
This is all by default; Visual Studio 2008 created all this.
I then created a simple Winforms app to "test" this. I added the Service Reference to my the above mentioned service and it all works. I can instanciate and call myservice1.GetData(100); and I get the result.
But I was told that this service will have to be consumed by a Winforms .NET 2.0 app via Web Services, so I proceeded to add the reference to a new Winforms .NET 2.0 application created from scratch (only one winform called form1). This time, when adding the "web reference", it added the typical "localhost" one belonging to webservices; the wizard saw the WCF Service (running on background) and added it.
When I tried to consume this, I found out that the GetData(int) method, was now GetData(int, bool).
Here's the code
private void button1_Click( object sender, EventArgs e )
{
localhost.Service1 s1 = new WindowsFormsApplication2.localhost.Service1();
Console.WriteLine(s1.GetData(100, false));
}
Notice the false in the GetData call?
I don't know what that parameter is or where did that come from, it is called "bool valueSpecified".
Does anybody know where this is coming from? Anything else I should do to consume a WCF Service as a WebService from .NET 2.0? (winforms).
Well well… apparently here's the answer and possible solutions or workarounds.

Categories