I have a WCF Service in which I want to maintain session for my Authentication method.
I have gone through from various articles and applied some of the below changes which are required to maintain session in WCF Service, as WCF not supported Session by default.
1- [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] in svc file.
2- [ServiceContract(SessionMode = SessionMode.Allowed)] in ServiceContract
3- Use the wsHttpBinding as basicHttpBinding not supported Session.
I am using WCFTestClient to call my service. I have checked the config of my TestClient and it is using basicHttpBinding, here is the cause of issue.
I am unable to implement the 3 point in my Service webconfig and also unable to change the config of my TestClient. Can anyone please guide me. Thanks
To solve this I implemented my own SessionHandler within the service.
a thread safe singleton class containing a Dictionary<Guid, SessionData>
Service Method: Guid RegisterClient(ClientName clientName) { /* add client to session */ }
Service Method: bool UnregisterClient(Guid clientGuid) { /* remove client from session */ }
Service Method: void DoThisOnServer(Guid clientGuid) { /* the service functionality */}
void CheckTimeout() { /* iterate over dictionary and remove out timed sessions */ }
Hints:
SessionData contains ClientName, TimeOfConnection, YourUsefulData
ClientName is a placeholder for IP-Adresse or some other initial identificator
Client has to register and all following operations are done only if the provided Guid exists in SessionHandler.
Related
Using .net 4.6, I have a windows service which has a timer that wakes up everyday at a configured time, connects to a remote database and caches some data in memory using the MemoryCache class:
string id = rec.ID;
string surname = rec.Surname;
string dateOfBirth = rec.DateOfBirth;
string agreement = rec.Agreement;
CachedData cd = new CachedData(id, surname, dateOfBirth, agreement);
MemoryCache.Default.Set(id, cd, new DateTimeOffset(DateTime.Now.AddDays(1)));
I need to expose a lookup interface on this MemoryCache. I have a separate WCF service which exposes a lookup interface but I don't know how to communicate the lookup request/result between the WCf service and windows service so if I get an id in the WCf service:
string id = HttpContext.Current.Request.QueryString.Get("id");
I could pass it on to the windows service which would look it up in memory cache and return a result.
I followed https://msdn.microsoft.com/en-us/library/ff649818.aspx to host a wcf service in a windows service. At the end I just added the following to the OnStart() method of the Service1.cs class of my WindowsService:
MemoryCache.Default.Set("K", "Hello World", new DateTimeOffset(DateTime.Now.AddDays(1)));
and assuming that because the WCF service (also called Service1.cs) is now hosted by the windows service and will share the same app domain, I modified the default GetData method in the WCF as follows:
public string GetData(int value)
{
var kv = MemoryCache.Default["K"] as string;
if (kv != null)
{
return kv;
}
else
{
return string.Format("Entered: {0}", value);
}
}
However when I use the test client and call the GetData it can't find the cached item in the MemoryCache.
You cannot get to MemoryCache instance from another process that hosts your WCF service.
Can you host WCF service inside Windows Service? In that case it won't be any issue to use MemoryCahce instance updated by timer in WCF service.
I would go for a (persistent) cache outside your application, that way you can have multiple instance, make deploys and so on without losing your cached data (what happens if your windows services goes tits up within those 24h today?). Memcached and Redis are the first ones that I think of.
I am developing a single-tenant web application that will be deployed in client data centers and for security reasons we would like to disable the metadata exchange on the applications WCF services. Is it possible to do this this programatically within our service application or another mechanism besides the web.config? We want to prevent more technically minded clients from going to the web.config and turning metadata exchange back on.
You can disable the metadata exchange programmatically by setting the HttpGetEnabled/HttpsGetEnabled to false.
First, Create a derive host from ServiceHost.
public class DerivedHost : ServiceHost
{
public DerivedHost( Type t, params Uri baseAddresses ) :
base( t, baseAddresses )
{
DisableMetadataExchange();
}
private void DisableMetadataExchange()
{
var metadata = Description.Behaviors.Find<ServiceMetadataBehavior>();
if metadata != null)
{
// This code will disable metadata exchange
metadata .HttpGetEnabled = false;
metadata .HttpsGetEnabled = false;
}
}
}
Second, Create a derived factory from ServiceHostFactory.
public class DerivedFactory : ServiceHostFactory
{
public override ServiceHost CreateServiceHost( Type t, Uri[] baseAddresses )
{
return new DerivedHost( t, baseAddresses );
}
}
Third, Create or Edit your your svc file Markup and apply your derived factory.
<% #ServiceHost Factory=”DerivedFactory” Service=”MyService” %>
Fourth, Test your service in the browser and you should see a message contain "Metadata publishing for this service is currently disabled".
If want more details about this implementation kindly visit this link.
Yes. If you code your WCF service as "self describing", which basically means using a WCF intercept layer to handle all the incoming requests to an endpoint, you can just return null from the MEX request.
To make this work is a bit tricky but in my experience leads to a much cleaner implementation than all those voluminous web.config entries. This is described here WCF Configuration without a config file.
I'm facing a little problem, and I hope that you will have a solution.
I'm using a wcf service to retrieve online data (from yahoo finance).
This service calls an API which connect to yahoo in order to retrieve the data I need.
However, when I call the API, I get the error
An exception occurred during a WebClient request.
I'm calling this service from console application.
I hope that you can help me with this issue.
== Here is the code
/* wcf service Interface */
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
// TODO: Add your service operations here
}
/* the service calls this function which belongs to another c# project */
public String updateDataBase()
{
DBHandler handler = new DBHandler();
/* Goes online et retrieve the data, when its called, the exception occurs */
handler.updateData();
return "success";
}
I solved my problem by running visual studio as Administrator.
Thank you.
Need a way for one service on a well-known Endpoint to return strings which are relative addresses. The client can then connect to Endpoints using these relative addresses.
Clearly this resembles REST in some ways, but in this case running a Windows Service using NetNamedPipeBinding for IPC, so no need for HTTP.
Don't want to create the Endpoint ahead of time since there will be a potentially large number of relative addresses, only some of which the client would be interested in.
All Contracts are known in advance.
Tried to find a solution with AddressFilterMode but wasn't sure how to provision new Binding so that client connected to it, UriTemplate but don't want to use the HTTP framework. Haven't looked into RoutingService because constrained to .Net 3.5.
Pseudocode for client would be something like that below...
namespace Testing
{
class RunTest
{
static void Test()
{
NetNamedPipeBinding namedpipe = new NetNamedPipeBinding();
ChannelFactory<Contracts.IRoot> factoryRoot =
new ChannelFactory<Contracts.IRoot>(
namedpipe
, new EndpointAddress("net.pipe://localhost/root");
);
Contracts.IRoot root = factoryRoot.CreateChannel();
ICommunicationObject commsRoot = root as ICommunicationObject;
commsRoot.Open();
// Service examines address and creates Endpoint dynamically.
string address = root.SomeFunctionWhichGetsARelativeAddress();
// IBar service routes endpoint requests internally based on
// "address" variable.
ChannelFactory<Contracts.IBar> factoryBar =
new ChannelFactory<Contracts.IBar>(
namedpipe
, new EndpointAddress("net.pipe://localhost/root/IBar/" +
address)
);
Contracts.IBar bar = factoryBar.CreateChannel();
bar.DoSomething();
}
} // Ends class RunTest
} // Ends namespace Testing
Message Filters are the way to go. You can use “Prefix” or create a custom.
WCF Addressing In Depth
From the Message Filters section of the article:
...it uses message filters to determine the matching endpoint, if one
exists. You can choose which message filter to use or you can provide
your own. This flexibility allows you to break free from the
traditional dispatching model when using Windows Communication
Foundation to implement things other than traditional SOAP—for
instance, the techniques described here enable you to implement
REST/POX-style services on the Windows Communication Foundation
messaging foundation.
Nice question, by the way. I learned something trying to figure this out.
AddressFilterMode.Prefix might suffice. The actual Endpoint used can be inspected in Service methods via
OperationContext.Current.IncomingMessageHeaders.To
Helper code can parse the endpoint and do any necessary internal processing from there.
Hopefully there's some extensibility on the server side which can simplify that code.
Pseudocode for host:
namespace Services
{
[System.ServiceModel.ServiceBehavior(AddressFilterMode =
System.ServiceModel.AddressFilterMode.Prefix)]
class BarService : Contracts.IBar
{
#region IBar Members
public void DoSomething()
{
System.Uri endpoint = System.ServiceModel.OperationContext.Current.IncomingMessageHeaders.To;
Console.WriteLine("DoSomething endpoint: {0}", endpoint);
}
} // Ends class BarService
} // Ends namespace Services
class RunHost
{
static void HostIBar()
{
System.Uri uriBase = new System.Uri("net.pipe://localhost");
System.ServiceModel.ServiceHost hostBar =
new System.ServiceModel.ServiceHost(
typeof(Services.BarService),
uriBase);
hostBar.AddServiceEndpoint(
typeof(Contracts.IBar) // Type implementedContract
, namedpipeBinding // System.ServiceModel.Channels.Binding binding
, "root/IBar" //string address
);
hostBar.Open();
Console.WriteLine("Press <ENTER> to stop...");
Console.ReadLine();
}
}
Correction: I'd originally said that this wouldn't treat "net.pipe://localhost/root/IBar/1" and "net.pipe://localhost/root/IBar/2" as distinct endpoints, but it does. Each causes its own WCF Service instance to be created and called.
An additional change was to encode the data in URL style query parameters and not embed it in the path. E.g.: "net.pipe://localhost/root/IBar?something=1&somethingelse=11" and "net.pipe://localhost/root/IBar?something=2&somethingelse=22" using HttpUtility.ParseQueryString
I was wondering if someone could show me how to log a simple request/response from my wcf rest service.
I am self hosting with a console application on the localmachine:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(RawDataService), new Uri(baseAddress));
WebHttpBinding binding = new WebHttpBinding();
//binding.Security.Mode = WebHttpSecurityMode.Transport;
host.AddServiceEndpoint(typeof(IReceiveData), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
host.Open();
Console.WriteLine("Host opened");
Console.ReadLine();
}
}
}
I was really hoping all that would be required is something added to the hosting console app. I tryed following this but it was abit confusing http://blogs.msdn.com/b/carlosfigueira/archive/2011/04/19/wcf-extensibility-message-inspectors.aspx
Just to note I am not using any app.config or web.config files.
EDIT:
I also cannot use any third party products for this.
Are you talking about logging for debugging purposes or for monitoring in a live service?
If you are debugging you can just switch on WCF tracing. It will produce a very comprehensive log and there is a good free tool for viewing the log that comes as part of the Windows SDK - I presume when you say you can't use third party product it doesn't include built-in .Net and Windows SDK features...
http://msdn.microsoft.com/en-us/library/ms733025.aspx
A common way to handle this is with Aspect-Oriented Programming (AOP) using the Castle Dynamic Proxy library. The idea is that you can decorate/proxy your service implementation with a dynamic class that intercepts every single method called on your service. No matter what method is called on your service, they'll be "intercepted" by your proxy and sent to a single method where you can log what you want and then you can finish the original call. Here's a quick sample of what that looks like:
public class LoggingInterceptor : IInterceptor
{
// No matter what service method is called, it's funneled through here.
public void Intercept(IInvocation call)
{
MyLogger.Info("Starting call: " + call.Method.Name);
// Actually invoke whatever method was originally called
call.Proceed();
MyLogger.Info("Finished call: " + call.Method.Name);
}
}
Now you need to create a proxy of your service class that uses this interceptor for all of its method calls. You can pretty up and abstract as necessary, but this is the basic jist:
using Castle.DynamicProxy;
...
// Create your service object and then create a dynamic proxy of the object
// that will inject your logging interceptor logic.
ProxyGenerator generator = new ProxyGenerator();
RawDataService service = new RawDataService();
RawDataService proxy = generator.CreateClassProxyWithTarget<RawDataService>(
service,
new LoggingInterceptor());
// Register your proxy object, not the raw service w/ WCF
WebServiceHost host = new WebServiceHost(proxy, new Uri(baseAddress));
... rest of your code as it was ...
Now any call made to your RawDataService will go through the Intercept() method first and when it calls Proceed() your actual implemented service logic will happen. You can update the interceptor to handle exceptions, include a StopWatch and log parameters as needed but that's the basic idea.
My example shows you the brute force way of setting this up. The "cleaner" solution would be to use IoC to create your service instance/proxy but this should get your code doing what you want right now. For further reading, here's a link to the Castle project's tutorial on using its AOP hooks: