Web Api and external event handling - c#

I've got a windows service, and I want to expose a web api on this service so our users can interact with the service via http.
I understand how to do a self host web api (http://www.asp.net/web-api/overview/hosting-aspnet-web-api/self-host-a-web-api), now my main problem is how to interface my ApiController with the class it will be executed from, so that when an http request is processed, an event is triggered, and something happens outside of the ApiController.
Based on the following example, how can I register my event handler UserRegistered in my service class ?
Web API Controller
public class MyController : ApiController
{
public delegate void OnPostRegister(Profile user);
public event OnPostRegister UserRegistered;
public void PostStream(Profile user)
{
try
{
IProfileBuilder builder = new ProfileBuilder();
builder.RegisterProfile(user);
if (UserRegistered!= null)
{
UserRegistered(user);
}
}
catch (Exception ex)
{
throw new HttpException(500, ex.Message);
}
}
Service Class
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
//initialize web api
var config = new HttpSelfHostConfiguration("http://localhost:8080");
config.Routes.MapHttpRoute(
"API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
using (var server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
}
//Load registered profiles
}
protected override void OnStop()
{
}
}

I don't think you can access the instance of the controller to subscribe to an event directly; I think you probably want a loosely coupled event handler; I was going to suggest the EventAggregator but that is part of Prism which is more for WPF although you could extract it. I did find this which looks like it could solve your issue.
http://blogs.taiga.nl/martijn/2011/07/28/loosely-coupled-events-in-net-and-harvesting-open-source-projects/

I'm sorry but you don't understand the concepts that stays behind web apis and cooperation with other services\apps in .NET world. You can not do like this: calling .NET event to trigger external service - it's crazy idea.
You have few choices here:
A) service bus - which pass events from web api to external service to handle it (NServiceBus, RabitMQ);
B) delegate processing to HangeFire;
C) any custom mechanism to inform external system about web api event\change (db triggers or any shitty ideas that will be difficult to maintain in the end like you are trying to do now)
D) you can create library with the logic from your super windows service and create API for it and you can create HTTP client to call call this API from anywhere - even you could refactor your old service.
Http processing has to be fast and simple. Delegation of the complex tasks should go to other services via additional mechanism\technology and not via .NET event. It is against going practices and impractical from many point of views.

Related

Instantiate SignalR Hub Object With IHubContext

It seems like a big use for SignalR Hubs is to display the actions of one client to all of the other clients. What I hope to use SignalR for is when a certain event happens in my server side code, I want to instantiate a hub object and invoke one of its methods to communicate with all of the clients. If you see my previous post (Route To Take With SqlDependency OnChange), I would like to do this in the OnChange method of SqlDependency. Upon researching it I have found some people talk about using an IHubContext object, though I haven't found many examples of instantiation and actual sending data to clients.
Is this possible to do (and what might sending data to all clients with IHubContext look like if possible), and if not, are there any ways I might be able to get around instantiating a hub like this?
SignalR for ASP.NET Core
You can create a class that has the IHubContext<T> injected in. Inject other dependencies if you want, or resolve the service from controllers or other classes.
public class NotificationService
{
private readonly IHubContext<MyHub> _myHubContext;
public NotificationService(IHubContext<MyHub> myHubContext)
{
_myHubContext= myHubContext;
}
public async Task SendMessage(string message)
{
await _myHubContext.Clients.All.SendAsync("Update", message);
}
}
Assuming you're using SqlDependency from an IHostedService:
public class MyHostedService : IHostedService
{
public MyHostedService(
NotificationService notificationService)
{
// TODO get reference to sqlDependency
sqlDependency.OnChange += (s, e) => _notificationService.SendMessage(e.Info.ToString());
}
}
SignalR for ASP.NET
var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
context.Clients.All.sendMessage(message);
You need to use using Microsoft.AspNet.SignalR library.
using Microsoft.AspNet.SignalR;
//Instantiating. SignalRHub is the hub name.
var context = GlobalHost.ConnectionManager.GetHubContext<SignalRHub>();
//sends message
context.Clients.Client(ClientId).sendMessage(data);

How to call a method of the ServiceHost from the hosting process in WCF C#

I have a publisher / subscriber pattern WCF Duplex ServiceHost that is hosted by a Windows Service. The Windows Service receives events from a separate process. OnEvent I would like to force my WCF Host to publish that data to all subscribed clients. Typically if a Client is calling this is straight forward. But when my Service Host needs to do this - I can't get my head around HOW to do that.
I have 2 questions:
1: I do not know how to create a Channel in WCFHost from my Windows Service so that it can use to publish to the Subscribers.
2: I read Creating WCF ChannelFactory so I do know I am creating a DuplexChannelFactory (2 per second ) which might be too much overhead.
Any help examples, hints are greatly appreciated. I am not a WCF expert and currently know more about it than I thought I should have to know in order to use it.
I had read on SO
Can I call a Method in a self hosted wcf host locally?
So then I have created a method inside my WCFHost like so:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
AutomaticSessionShutdown = false,
IncludeExceptionDetailInFaults = true)]
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ServerHost<TService> : ServiceHost where TService : class
{
public T GetDuplexClientChannel<T, Cback>(BindingType bindingType, EndpointAddress endPointAddress) where T : class
{
ServiceEndpoint sep = GetContractServiceEndPoint<T>(bindingType, endPointAddress);
lock (_syncRoot)
{
DuplexChannelFactory<T> factory = new DuplexChannelFactory<T>(typeof(Cback), sep);
return factory.CreateChannel(endPointAddress);
}
}
}
I get an error of course that there is no InstanceContext because I am constructing using typeof(Cback) ..
"This CreateChannel overload cannot be called on this instance of DuplexChannelFactory, as the DuplexChannelFactory was initialized with a Type and no valid InstanceContext was provided."
So I am not sure how I can go about performing this ?
And for those that say read the error : yes I read the error.
Now how to do that with an InstanceContext that does not exist as OperationContext.Current does not exist at this point as I am calling this method form my Hosting Process into my WCFHost.
So if I could have a nice example of how to do this - even if I must use the code example on the 2nd link (of course implementing the DuplexChannelFactory) I would greatly appreciate it.
EDIT
Basically the windows Service is doing some heavy work monitoring other services, about 2 times a second it then must publish that to "Subscribed" Clients via WCF.
I think you have got very confused about how everything is wired together and are mixing concepts from the client in with the service. You haven't provided much concrete information about your scenario to go on so I'm going to provide a small example and hopefully you will be able to apply the ideas to your problem.
[ServiceContract(CallbackContract=typeof(IMyServiceCallback))]
public interface IMyService
{
[OperationContract]
void Register();
}
public interface IMyServiceCallback
{
[OperationContract]
void ReceiveData(string data);
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyService : IMyService
{
static HashSet<IMyServiceCallback> s_allClients = new HashSet<IMyServiceCallback>();
static object s_lockobj = new object();
public void Register()
{
lock(s_lockobj)
{
_allClients.Add(OperationContext.Current.GetCallbackChannel<IMyServiceCallback>());
}
}
public static void SendDataToClients(string data)
{
HashSet<IMyServiceCallback> tempSet;
lock(s_lockobj)
{
tempSet = new HashSet<IMyServiceCallback>(_allClients);
}
foreach(IMyServiceCallback cb in tempSet)
{
try
{
cb.ReceiveData(data);
}
catch(Exception)
{
lock(s_lockobj)
{
_allClients.Remove(cb);
cb.Abort();
cb.Dispose();
}
}
}
}
}
In your OnEvent method, you would call something similar to this inside your event method.
MyService.SendDataToClients(mydata);
This uses static data to store the list of clients. If you wanted to do something like segment your clients for different endpoints, you would need to do something different. There is a potential out of order message and scaling problem with this code if your OnEvent method can be called again while the previous call hasn't completed. For example, if you receive 2 messages, the first being large and the second being small, you could potentially send the second smaller message to clients later in the HashSet iteration order before they have been sent the first message. Also this won't scaled to a large number of clients as you could block timing out on one client holding up messages being sent to other clients. You could use something similar to Task's to dispatch multiple message deliveries. If this needs to scale, I would suggest looking at Reactive Extensions for .Net

Can I extend ServiceStackHost to handle requests from a CEF browser in my application?

I have a solution which includes a thick client (implemented using CefSharp for the majority of the user interface), and the javascript application needs to execute some C# logic in the application hosting the CEF browser. I considered using WebView.RegisterJsObject(), but I can write less glue code if I can just use $.ajax() from the html pages.
I already have ServiceStack set up for the web services and the web client in this solution. I'd like to route requests from the CEF browser to a local ServiceStack host (without actually using http).
Here's some psuedo code to illustrate what I would like to do:
public partial class MainWindow : IRequestHandler {
WebView _webView;
CefSharpServiceStackHost _serviceHost;
public MainWindow() {
// initialize CefSharp...
_webView.RequestHandler = this;
// initialize ServiceStackHost...
}
// other IRequestHandler methods...
// method this intercepts ajax calls from the CEF browser
public bool OnBeforeResourceLoad(IWebBrowser browser, IRequestResponse requestResponse) {
// translate CefSharp.IRequestResponse to ServiceStack.IRequest or HttpRequest
// should execute HelloService.Any() for the requestResponse.Url = "/hello/Zach"
var response = _serviceHost.ExecuteService(Translate(requestResponse));
requestResponse.RespondWith(response.Stream);
return false;
}
}
[Route("/hello/{Name}")]
public class Hello {
public string Hello { get; set; }
}
public class HelloService {
public object Any(Hello request) { // ... }
}
The part I can't figure out is how to extend ServiceStackHost so I can pass some sort of request object to it. Is this even possible?
This might be a stupid answer, but why not just use http anyway? The web is so heavily based on it that things actually gets easier if you use it even in cases like this (where it isn't really necessary).
If this isn't OK, you can implement a custom scheme handler that routes requests to foo://bar to your C# code, and do whatever you like. The CefSharp.Wpf.Example has an example custom scheme handler, so it should help you along the way.
What you're after sounds similar to how MQ Servers execute services in ServiceStack by simply routing messages to:
ServiceController.ExecuteMessage(IMessage)
There are a number of other API's on ServiceController you can use to execute requests in ServiceStack:
//Execute the Request DTO with an empty Request context:
object Execute(object requestDto)
//Execute the Request DTO with the supplied Request context:
object Execute(object requestDto, IRequest request)
For the IRequest context, you can use the built-in BasicRequest class, or your own that implements IRequest.

stub webserver for integration testing

I have some integration tests where I want to verify certain requires are made against a third-[arty webserver. I was thinking I would replace the third-party server with a stub server that simply logs calls made to it. The calls do not need to succeed, but I do need a record of the requests made (mainly just the path+querystring).
I was considering just using IIS for this. I could 1) set up an empty site, 2) modify the system's host file to redirect requests to that site 3) parse the log file at the end of each test.
This is problematic as for IIS the log files are not written to immediately, and the files are written to continuosly. I'll need to locate the file, read the contents before the test, wait a nondeterministic amount of time after the test, read the update contents, etc.
Can someone think of a simpler way?
You could use the System.Net.HttpListener ( MSDN LINK ).
It works as embedded WebServer, this means you can even check the access on-the-fly without having to parse log files.
A class i used in my Code recently:
class Listener
{
private HttpListener listener = null;
public event EventHandler CommandReceived;
public Listener()
{
this.listener = new HttpListener();
this.listener.Prefixes.Add("http://localhost:12345/");
}
public void ContextReceived(IAsyncResult result)
{
if (!this.listener.IsListening)
{
return;
}
HttpListenerContext context = this.listener.EndGetContext(result);
this.listener.BeginGetContext(this.ContextReceived, this.listener);
if (context != null)
{
EventHandler handler = this.CommandReceived;
handler(context, new EventArgs());
}
}
public void Start()
{
this.listener.Start();
this.listener.BeginGetContext(this.ContextReceived, this.listener);
}
public void Stop()
{
this.listener.Stop();
}
}
Yeah, I don't think you need a whole webserver. You don't need to test HTTP.
What you do need to test is the underlying data structure that you're sending and receiving. So just create tests for that (i.e. make a point at which you can validate your generate dataformat with what is expected, and also with what you intend to receive, etc).
Test the data, not the protocol (unless, obviously, the protocol is custom).
I've done something very similar to this in a number of projects.
You don't want to create stubbed web service. That's just adding a dependency you don't need. What I did was create an interface which mimics the web service's API. I then created a proxy class that will call the web service in the live system. For testing I used RhinoMocks to create mocked classes that return the results I wanted to test for. This was very useful for me, as I could then produce all sorts of 'unexpected' behaviour which wouldn't be possible with the live system.
public interface IServiceFacade {
string Assignments();
}
public class ServiceFacade : IServiceFacade {
private readonly Service _service;
public ServiceFacade(Service service) {
_service = service;
}
public string Assignments() {
return _service.Assignments();
}
}
Then my test code contained stuff like this:
var serviceFacade = MockRepository.GenerateMock<IServiceFacade>();
serviceFacade.Stub(sf => sf.Assignments()).Return("BLAH BLAH BLAH");
or
serviceFacade.Stub(sf => sf.Assignments()).Return(null);
or
serviceFacade.Stub(sf => sf.Assignments()).Throw(new Exception("Some exception"));
I found this very useful.

Analyze the use of a ASP.NET webservice

long time ago I wrote webservice that is still in use. Now I plan to refactor it. The webservice is full of most likely unused functions and I have no idea how it is used by the clients. In order to strip away the unused functions I need to analyze the function calls and data of currently installed webservice.
Is there a (free/opensource) tool that will enable me to log all activities of the webservice.
The ideal output of the tool I'm looking for could be a database containing all the called functions and a list of the data that was send to it for each call.
Solution
With the help of Martins answer I created this HttpModule which does exactly what I wanted:
public class LoggingModule : IHttpModule
{
void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(BeginRequest);
}
private void BeginRequest(object sender, EventArgs e)
{
TryAppendLog("Content-Type");
TryAppendLog("SOAPAction");
}
void TryAppendLog(string key)
{
string value = HttpContext.Current.Request.Headers[key];
if (string.IsNullOrEmpty(value)) { return; }
HttpContext.Current.Response
.AppendToLog(string.Format("{0}: {1} ", key, value));
}
#region IHttpModule Member
public void Dispose() { }
#endregion
}
As Kobi wrote, you can find the required information in the IIS log files (i.e. in c:\WINDOWS\system32\LogFiles\W3SVC1).
If you want to log the usage into a database, you could write a simple HttpModule, which checks every request, and logs it into the DB if it is a call to your web service.
E.g. here's the relevant parts of a very simple HttpModule, which logs calls to mywebservice.asmx:
public class MyWebServiceDiagnosticsModule : IHttpModule
{
public MyWebServiceDiagnosticsModule ()
{
}
void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(BeginRequest);
}
private void BeginRequest(object sender, EventArgs e)
{
HttpContext ctx = HttpContext.Current;
string url = ctx.Request.Url.ToString().ToLower();
if (url.Contains("mywebservice.asmx"))
{
LogMethodCall(url); // parse URL and write to DB
}
}
}
You can potentially write your own IHttpHandler that would log all the information and then delegate the call to appropriate .NET HTTP Handler, but that wouldn't be a simple task.
And a word on terminology. "Refactoring" is not about changing external behavior, so if refactoring is really what you're heading for, I'd recommend to keep the public contract (interface) of the web service intact. Instead, roll out a new version of the same service with only core functionality.
You can enable logging in the IIS, they can get very detailed depending on your choices.
There are tools made specifically for analyzing IIS logs.
Depending a little bit on your load/criticality and similar constraints you could also probably just route the traffic through as Soap Proxy like SoapUI to capture and analyze traffic for a period of time. If you set up the proxy and re-route at the firewall level it should be transparent for end-users.
I have not tried this for a system with heavy load; be warned.

Categories