I have created a WCF service in c#. Iam able to access it form a client app with url http://localhost:8080/classname/function
Is there any way to detect whether the client is connected from WCF service in which the client has the url http://localhost:8080 alone without class name and function name where the WCF service is listening to 8080 port at localhost?
Based upon your request to explain how to send an empty string message to a WCF service I have developed a VS2017 solution and uploaded onto the GITHUB for you.
The solution contain 3 projects, 2 on the WCF Service side (Class library and Console Application) and 1 for client.
WCF Service Side
First we define a ServiceContract that will have single OperationalContract to receive the string message and returns a boolean:
[ServiceContract]
public interface IClientConnectionService
{
[OperationContract]
bool Connect(string message);
}
Next, we have a class that implements this ServiceContract
public class ClientConnectionService : IClientConnectionService
{
public bool Connect(string message)
{
/*
* As per your comment on http://stackoverflow.com/questions/43366101/how-to-check-wcf-service-is-connected-with-client?noredirect=1#comment74005120_43366101
* the message should be empty, however you can pass string.
* Once you are done with processing you can return true or false depending upon how you want to carry out
* this operation.
*/
return true;
}
}
Next, we have the WCF service host manager (a console based application just to host this WCF service)
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(ClientConnectionService)))
{
host.Open();
Console.WriteLine($"{host.Description.Name} is up and listening on the URI given below. Press <enter> to exit.");
PrintServiceInfo(host.Description);
Console.ReadLine();
}
}
private static void PrintServiceInfo(ServiceDescription desc)
{
foreach (ServiceEndpoint nextEndpoint in desc.Endpoints)
{
Console.WriteLine(nextEndpoint.Address);
}
}
}
Its responsibility is to just keep the WCF service listening for incomming requests on a net.tcp port defined in the config file:
<system.serviceModel>
<services>
<service name="StackOverflow.Wcf.Services.ClientConnectionService">
<endpoint
address="net.tcp://localhost:9988/ClientConnectionService/"
binding="netTcpBinding"
contract="StackOverflow.Wcf.Services.Contracts.IClientConnectionService"
></endpoint>
</service>
</services>
</system.serviceModel>
Once this is completed we have a running WCF service. Now lets turn our attention to the client that will consume this service.
WCF Client Side
This is just a console application that has a reference of WCF Service and it creates the proxy class to call the method on the service.
public class ClientConnectionServiceProxy : ClientBase<IClientConnectionService>
{
public bool Connect(string message)
{
return base.Channel.Connect(message);
}
}
Notice that we have used IClientConnectionService interface / contract from the service side. ClientBase<T> is a WCF Framework class.
Here is the program class that calls the WCF servie using above defined proxy class.
class Program
{
static void Main(string[] args)
{
using (ClientConnectionServiceProxy proxy = new ClientConnectionServiceProxy())
{
bool isCallSuccessful = proxy.Connect(string.Empty);
}
}
}
and here is the client configuration:
<system.serviceModel>
<client>
<endpoint
address="net.tcp://localhost:9988/ClientConnectionService/"
binding="netTcpBinding"
contract="StackOverflow.Wcf.Services.Contracts.IClientConnectionService"
></endpoint>
</client>
</system.serviceModel>
How to run:
Once you have downloaded the source code from GITHUB, open the StackOverflow.Wcf.sln file in VS2017 (thats what I have used to develop this - not sure if you can open it in the VS2015) and hit F5. You can put break points to step through the code and edit it as you wish.
Hope this makes it clear - leave any questions in the comments below.
Related
I built a WCF service library and hosted it through a host application. Then I constructed a client application, but it seems that the address of the service host is hard coded in the client program. What if the host changes its address? Is it possible to write the client application so that the address of the host can be entered by the client at run time?
Yes, it's possible, if you write the WCF client proxy by hand, instead of generating it automatically with Visual Studio adding a service reference.
Let's start from this example (https://learn.microsoft.com/it-it/dotnet/framework/wcf/feature-details/how-to-use-the-channelfactory), just to understand how ChannelFactory works, and then modify it a little bit, adding the following function.
private ChannelFactory<IMath> _myChannelFactory;
// ...
private IMath GetChannel(string endpointConfigurationName, string endpointAddress)
{
if (_myChannelFactory == null)
{
this.DebugLog("Channel factory is null, creating new one");
if (String.IsNullOrEmpty(endpointAddress))
{
_myChannelFactory = new ChannelFactory<IMath>(endpointConfigurationName);
}
else
{
_myChannelFactory = new ChannelFactory<IMath>(endpointConfigurationName, new EndpointAddress(endpointAddress));
}
}
return _myChannelFactory.CreateChannel();
}
You can define the default server IP in the client App.config file
<system.serviceModel>
<!-- ... -->
<client>
<endpoint address="net.tcp://192.168.10.55:81/math/" binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_IMath"
contract="MyNamespace.IMath" name="NetTcpBinding_IMath" />
</client>
</system.serviceModel>
In this way, when GetChannel("NetTcpBinding_IMath", "net.tcp://127.0.0.1:81/math") is called, it picks up the endpoint configuration from App.config file, replacing the default address (192.168.10.55) with the new one (127.0.0.1).
Some more documentation about ChannelFactory: https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.channelfactory-1.createchannel?view=netframework-4.8
I've looked at a lot of questions on this site that discuss, but don't directly answer this question. I have the following:
In Library.dll:
namespace LibraryNamespace
{
[ServiceContract]
public interface IService
{
[OperationContract]
void Operation();
}
}
In Implementation.dll:
namespace ImplementationNamespace
{
public class ServiceImplementation : IService
{
public void Operation()
{
// Do Something
}
}
}
In app.config:
<service name="ImplementationNamespace.ServiceImplementation">
<endpoint
address="ServiceImplementation"
binding="netTcpBinding"
contract="LibraryNamespace.IService" />
....
</service>
And I keep having a warning with contract="LibraryNamespace.IService". The program runs, but I have a feeling this warning is causing me more problems down the line.
The 'contract' attribute is invalid - The value
'LibraryNamespace.IService' is invalid according to its datatype
'serviceContractType' - The Enumeration constraint has failed.
It works when the ServiceContract and the service implementation are in the same assembly and namespace, but for some reason, it doesn't work here. How can I reference it properly?
I am not sure Why do you want to have the contract and implementation in separate dll? any specific reason? Generally they will be in same assembly and so in config file you can refer them with ease. One way to solve this is creating the service endpoint at runtime like below.
In your hosting project refer both the dll Library.dll and Implementation.dll and have the below code to add the endpoint
using LibraryNamespace;
using ImplementationNamespace;
// Specify a base address for the service
String baseAddress = "http://localhost/ServiceImplementation";
// Create the tcp binding
NetTcpBindings tcp = new NetTcpBindings();
// Define service and Create the endpoint
using(ServiceHost host = new ServiceHost(typeof(ServiceImplementation)))
{
host.AddServiceEndpoint(typeof(IService),tcp, baseAddress);
}
I am trying to make a WCF Service that both publishes messages to a topic and also subscribes to that topic. The idea is to have my service expose endpoints for managing a customer (i.e. CreateCustomer, EditCustomer, DeleteCustomer, etc). Then I want it to publish a message to a topic after it completes each operation (i.e. OnCustomerCreated, OnCustomerChanged, OnCustomerDeleted, etc.)
For Example, A client application will hit the EditCustomer message on my service. I will immediately publish an OnCustomerChanged message with the customer object provided. My service (the same one the customer hit) will have another contract that takes an OnCustomerChanged and updates my database.
My question is, do I have to make a separate Subscription on my topic for each message type (i.e. OnCustomerChangedSubscription, OnCustomerDeletedSubscription, etc.) so that I can properly route messages of different types to the correct endpoint?
If that is case, I would need a bunch of single-method contracts so that I could configure the wcf endpoints properly:
i.e:
<service name="site.Services.Business.Managers.CustomerManager">
<!-- endpoint that clients will hit -->
<endpoint address="" binding="basicHttpBinding" contract="site.Services.Business.Contracts.ICustomerManager" />
<!-- endpoint that publishes messages-->
<endpoint address="sb://test-site.servicebus.windows.net/Managers/CustomerManager"
binding="netTcpRelayBinding"
contract="site.Services.Business.Contracts.ICustomerManager"
behaviorConfiguration="sbTokenProvider" />
<!-- One Endpoint for each message type (this will get very cumbersome and the contract will only have 1 method on it) -->
<endpoint address="sb://test-site.servicebus.windows.net/Managers/CustomerManager"
binding="netMessagingBinding"
listenUri="sb://test-site.servicebus.windows.net/Managers/CustomerManager/subscriptions/OnCustomerDeleted"
behaviorConfiguration ="sbTokenProvider"
contract="site.Services.Business.Contracts.CustomerManager.IOnCustomerDeleted" />
<endpoint address="sb://test-site.servicebus.windows.net/Managers/CustomerManager"
binding="netMessagingBinding"
listenUri="sb://test-site.servicebus.windows.net/Managers/CustomerManager/subscriptions/OnCustomerCreated"
behaviorConfiguration ="sbTokenProvider"
contract="site.Services.Business.Contracts.CustomerManager.IOnCustomerCreated" />
…etc
</service>
An alternative would be to create a single Subscriber (Allmessages), only having one contract with a HandleMessage(BrokeredMessage message) operation, and then determine inside that method with method to call on my service. That doesn't seem like I am doing the right thing there though either. I am essentially taking in all messages and determining the handler inside the service.
What I am looking for is a way to have a a service that implements 3 contracts, ICustomerPublisher (already have this), ICustomerManager (exposed over http to clients), and ICustomerSubscriber.
ICustomerSubscriber would look like:
[ServiceContract]
public interface ICustomerSubscriber
{
[OperationContract(IsOneWay = true)]
void OnCustomerCreated(ICustomerMessage message);
[OperationContract(IsOneWay = true)]
void OnCustomerDeleted(ICustomerMessage message);
[OperationContract(IsOneWay = true)]
void OnCustomerChanged(ICustomerMessage message);
}
and I would be able to call:
publisher.Publish<OnCustomerChanged>(new CustomerChangedMessage(customer));
and have my OnCustomerChanged method receive that message.
Any help would be appreciated.
First: Yes, if the service has per-request activation, then your SubscriptionClient won't get a chance to run except while the service responds to an external request, and it will have to be created and torn down every time. The only feasible way to keep the SubscriptionClient running would be to change activation to singleton.
But I think the better approach is to pull the SubscriptionClient out of this service entirely and have it run on its own. If you want it to run on-prem, then it could be in a Windows Service or console app; in the cloud, it could be a WebJob or Worker Role. Again, I don't see why your OnMessage method needs to be a WCF Operation.
Second: If there's only one Subscription, then each message can be received and completed by only one client. If multiple clients need to get a copy of each message, then each client needs its own subscription. The subscriptions can share the same filter conditions, or no conditions.
I was not able to find a suitable way to accomplish what I mentioned above. Instead, I did the following:
Created a default subscription to my customer topic with no filter.
In the constructor for my WCF service, I use the SubscriptionClient to register as a subscriber:
public CustomerManager()
{
//set up automapper and IoC
Initializer.Initialize();
Publisher = IoCContainer.GetContainer().Resolve<IPublisher>("CustomerManager");
Publisher.Subscribe("AllMessages");
var client =
SubscriptionClient.CreateFromConnectionString(CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ConnectionString"), "customertopic", "AllMessages", ReceiveMode.PeekLock);
client.OnMessage(m =>
{
Console.WriteLine("Message Received.");
HandleMessage(m);
});
}
My HandleMessage method takes a BrokeredMessage as a parameter and then determines what internal operation to call based on the message body type.
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void HandleMessage(BrokeredMessage message)
{
var customerMessage = message.GetBody<CustomerMessage>();
switch (customerMessage.EventName)
{
case "OnCreated" :
OnCustomerCreated(customerMessage);
break;
case "OnDeleted" :
OnCustomerDeleted(customerMessage as OnDeleted);
break;
case "OnChanged" :
OnCustomerChanged(customerMessage as OnChanged);
break;
}
message.Complete(); //mark the message as completed
}
I have a couple of concerns though.
First, I use instance per request configuration for my service. Will this cause any kind of message consistency issues? Such as, when I have multiple instances of CustomerManager, will each one try and handle the same message, or will the SubscriptionClient ensure that only 1 CustomerManager will get the message?
Second, I want to be able to subscribe other services to my AllMessages subscription. One example is a notification service. I may want to be able to send a push notification to the account owner when a new customer is created (OnCustomerCreated), or I might want to ask the customer to verify the information that changed on their account (OnCustomerChanged). Can I still subscribe other services to the CustomerTopic AllMessages, or will marking the message complete (as I do at the end of my HandleMessage method) clear out the message for other subscribers also? More technically, will adding another subscriber to the AllMessages subscription result in multicasting or balancing?
Hi I would like to create an API for my website to send and receive data.
For example I need my customers to upload products, single or multiple items. Product feeds can be send daily, weekly or monthly.
Product Name:
Product Color:
Product Weight:
Product Images:
Also I need functionality to send this data to another server. And it should be user friendly.
But I don't have any idea where to start, what technology to use to make it simple and sufficient.
I have background in Asp.Net, C#. It would be great to see an example how to approach it.
Its better you go for the WEB SERVICES (WCF SERVICE) to achieve this easily.
REST via WCF would be the best option. Here is a good article series introducing you to REST with WCF: REST in WCF
There are two distinct pieces of functionality here, and keep in mind that they should essentially be kept separate. Each of them is defined by "who is integrating to whom."
In the first piece, you want to expose a web service API to which clients can connect and send/receive data (the latter of which is on request only). How you want to define this web depends on how you want to expose it to clients, how they want to connect, etc. Common options are:
SOAP Web Service (classic ASP .NET web service)
WCF Service (think of it as a more modern ASP .NET web service)
You can even expose a manual service by defining your own WSDL for clients to consume, or a service that accepts and returns JSON to be more JavaScript-friendly for clients, etc. There are many options. But the above two are your most common choices.
The second piece is where you want to "push" data to another service. This is something that the other service needs to expose and you need to integrate to that. So the design should begin on that side. If you're in charge of that design, just approach it the same way as above. Expose a service there and then, using the same technologies that expose the services, consume them in your application.
The main thing to keep in mind here is to keep the two separate, because trying to expose a web service which at the same time consumes another web service will likely lead to confusion and some non-obvious work-arounds. These are separate concerns and need to keep separated on a logical level, even if the end user doesn't know how separated they are.
Here is a bare minimum WCF Service which returns a product in JSON. To try it out, create a .NET 4.0 Full Profile console application. Run the program, and put this in your browser's address bar: http://localhost:8080/productservice/Product/23
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace WCFServiceExample
{
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
}
[ServiceContract(Namespace = "")]
public interface IProductService
{
[WebGet(UriTemplate = "Product/{id}", ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
Product Product(string id);
}
public class ProductService : IProductService
{
public Product Product(string id)
{
return new Product { Id = id, Name = "A Sample Product" };
}
}
class Program
{
private static ServiceHost servHost;
static void Main(string[] args)
{
StartService();
Console.WriteLine("\n\nPress any key to exit...");
Console.ReadKey();
}
public static void StartService()
{
servHost = new ServiceHost(typeof(ProductService));
servHost.Open();
}
~Program()
{
if (servHost != null)
{
servHost.Close();
}
}
}
}
App.config
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true" logKnownPii="true" logMalformedMessages="true"
logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" />
<endToEndTracing propagateActivity="true" activityTracing="true"
messageFlowTracing="true" />
</diagnostics>
<services>
<service name="WCFServiceExample.ProductService">
<endpoint
address="http://localhost:8080/productservice"
contract="WCFServiceExample.IProductService"
kind="webHttpEndpoint" />
</service>
</services>
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
We are using WCF for communication between a client and a server application. The client application has many features that requires communication to the server - and we have chosen to implement this in multiple classes (seperation of responsability)
For the time, we are creating new WCF endpoints and service contracts for each object - Invoicing, Accounting, Content Management, etc. This causes a lot of endpoint configuration both on the client and server (with potential misconfiguration problems when moving into the test and production platforms).
I would like to know if I can define a single WCF endpoint that can deliver multiple service contact implementations. Our configuration files would then contain a single endpoint (to the service factory) and I can request different services by specifying the interface of the service I am interested in.
e.g.
using (IServiceClientFactory serviceClientFactory = new RealProxyServiceClientFactory())
{
// This is normal WCF proxy object creation.
IServiceFactory serviceFactory = serviceClientFactory.CreateInstance<IServiceFactory>("");
// This is what we would like to do
IInvoiceService invoiceService = serviceFactory.getService(typeof(IInvoiceService));
invoiceService.executeOperation(data);
}
The clue being a single endpoint configuration per client/server pair, instead of an endpoint configuration per service contact I would like to make available.
Is this possible?
I'm not 100% clear on what you're trying to do, but if you just want to be able to host different contracts on the same address with the implementation inside one service class, this is completely possible. To share an endpoint address, you must ensure that you use the same binding instance for each service endpoint.
Here is a complete sample which defines 3 contracts, 1 service class which implements all of them, and a ServiceHost with the 3 contract endpoints at the exact same address:
using System;
using System.ServiceModel;
[ServiceContract]
interface IContractA
{
[OperationContract]
void A();
}
[ServiceContract]
interface IContractB
{
[OperationContract]
void B();
}
[ServiceContract]
interface IContractC
{
[OperationContract]
void C();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class Service : IContractA, IContractB, IContractC
{
public Service()
{
}
public void A()
{
Console.WriteLine("A");
}
public void B()
{
Console.WriteLine("B");
}
public void C()
{
Console.WriteLine("C");
}
}
class Program
{
public static void Main(string[] args)
{
Uri address = new Uri("net.pipe://localhost/Service/");
ServiceHost host = new ServiceHost(new Service(), address);
NetNamedPipeBinding binding = new NetNamedPipeBinding();
host.AddServiceEndpoint(typeof(IContractA), binding, string.Empty);
host.AddServiceEndpoint(typeof(IContractB), binding, string.Empty);
host.AddServiceEndpoint(typeof(IContractC), binding, string.Empty);
host.Open();
IContractA proxyA = ChannelFactory<IContractA>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyA.A();
((IClientChannel)proxyA).Close();
IContractB proxyB = ChannelFactory<IContractB>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyB.B();
((IClientChannel)proxyB).Close();
IContractC proxyC = ChannelFactory<IContractC>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyC.C();
((IClientChannel)proxyC).Close();
host.Close();
}
}
I doubt that this would work. Xml serialization might be the biggest problem here.
Also I don't think you actually need it. If I was in your shoes I would try and abstract my communication with the service. Basically you would always send a "Message" to the service, which has a "Target" being one of the classes you wanted to access. The service would always reply with a "Response", of which the contents would be filled by the class the "Message" was send to.
Another approach would be to route all these messages trough a service that would echo the request to the appropriate service. This way you keep scalability up, but it does still have a large configuration burden.
HTH.
Sounds like you want to keep your seperate services but have some kind of bus that routes is throught. MSMQ maybe, then you can have one services that takes every message pops it onto a specific queue and then a dedicated service can read that off that particular queue.
Not really a WCF based solution though admittedly.
The notion of a single interface(read as ServiceContract) implemented by multiple classes wont work. So you'd need one 'monster' service that implements all and routes through to the correct service. Facade pattern springs to mind.