I am trying to build (csharp) one webservice /WCF engine that make two actions:
Have one timer (thread), that will run in each 10-10 minutes, requesting some information (connecting with other server to grab some info - status) to update in one database. (This must be automatic and no human action will be available). The idea is the webservice automaticaly (10x10 minutes) update the database with the recent information status.
One service method that get some information from one database. (This is one simple method that gives the information when someone request it). This method will responsible to select the status info from database.
The problem is the step 1, because step 2 is very easy.
Can anyone help me, with ideas or some code, how to the step 1.
Any pattern should be used here?
Since it's a webapp (for instance, a "WCF Service Application" project type in VS2010), you can hook into the application events.
By default that project template type doesn't create a Global.asax, so you'll need to "add new item" and choose "Global Application Class" (it won't be available if you already have a Global.asax, FWIW).
Then you can just use the start and end events on the application to start and stop your timer, so something like:
public class Global : System.Web.HttpApplication
{
private static readonly TimeSpan UpdateEngineTimerFrequency = TimeSpan.FromMinutes(10);
private Timer UpdateEngineTimer { get; set; }
private void MyTimerAction(object state)
{
// do engine work here - call other servers, bake cookies, etc.
}
protected void Application_Start(object sender, EventArgs e)
{
this.UpdateEngineTimer = new Timer(MyTimerAction,
null, /* or whatever state object you need to pass */
UpdateEngineTimerFrequency,
UpdateEngineTimerFrequency);
}
protected void Application_End(object sender, EventArgs e)
{
this.UpdateEngineTimer.Dispose();
}
}
The Single Responsibility Principle suggests that you should split these two responsibilities into two services. One (a Windows Service) would handle the Timer. The second, the WCF Service, would have the single operation to query the database and return the data.
These are independent functions, and should be implemented independently.
Additionally, I would recommend against depending on IIS or Application_Start and similar methods. That will prevent your WCF service from being hosted in WAS or some other environment. Keep in mind that WCF is much more flexible than ASMX web services. It doesn't restrict where you host your service. You should think carefully before you place such restrictions on your own service.
Related
I have an IIS server (7.5) that hosts several applications each of them run in their own application pool identity. I am trying to write some code that intercepts the Session On Start event. I have successfully written other IHttpModules that are processed for all requests but, in this case I only want to intercept the first time the session is initiated. I want to do this for all the web applications at a global level within my web site. My plan is to use this to capture the last logon date for the user on a per web app basis to satisify an auditing requirement.
I have all the pieces in place except the event that I need to intercept. It seems all IHttpModule Events fire on all requests. I figured the Session_Start event would be ideal but it doesn't look like I can tie into this from an IHttpModule.
I looked at the SessionStateUtility but I do not want to rewrite session functionality, I just want to intercept the start event.
Is there another interface out there I can use to intercept Session_Start? Any other recommendations?
Have you tried something like this?
public void Init(HttpApplication context)
{
var sessionModule = context.Modules["Session"] as SessionStateModule;
if (sessionModule != null)
{
sessionModule.Start += this.Session_Start;
}
}
private void Session_Start(object sender, EventArgs e)
{
// Do whatever you want to do here.
}
The scenario is a SQL Server that has to be updated regularly with data obtained from some API calls. Each request to the API may take about 30-200 minutes so they are not instant, and it has to be always asking the API for the new data.
The calls to the API are performed with some input parameters the user of the MVC App(like dates or names)
I was thinking in doing it as a Windows Service, that is launched/stopped from the MVC, but i donĀ“'t know if it is the best approach, cause i don't know if they can easely communicate.
An better approach will be like a Task Item that can perform heavy operations and communicate with the mvc directly. It would be so useful to see a log.
What you, experts, would recommend?
Thanks
I would use a windows service and execute a command from the website. It's quite easy:
MVC
sth like
using System.ServiceProcess;
...
public ActionResult Update()
{
int updateCommandId = 1; //example
ServiceController sc = new ServiceController("windowsServiceName");
sc.ExecuteCommand(updateCommandId);
}
and for your windows service just override OnCustomCommand:
protected override void OnCustomCommand(int commandId)
{
if(commandId == 1)
{
//do your update
}
}
I am making a project using WebServices in C#. I wanted to ask you, how can I give a value to a variable from Client to a Web Service?
For example:
In the web service I have a variable and two Methods, getVariable() and setVariable(bool a);
bool var = false;
[WebMethod]
public void setVariable(bool a)
{
var = a;
}
[WebMethod]
public bool getVariable()
{
return var;
}
This is how my web service looks (it's simple because I am learning).
My client:
//In the client I added the web service as a Service Reference and added this code:
ServiceReference.ServiceSoapClient obj = new ServiceReference.ServiceSoapClient();
private void Form_Load(object sender, EventArgs e)
{
obj.setVariable(true);
label1.Text = obj.getVariable().ToString();
}
And when I load my form, the label1.Text isn't equal with "True" but with "False"!! Which means that it didn't execute this code: obj.setVariable(true);
My professor said in the class something that WebService are now "full...." (but I couldn't hear it well), he said you have to find a way to make WebServices "ful..."
Can someone help me ?
Web services are stateless by default, which means that they don't retain state between calls. So a value set in one call won't be available for usage by the next call.
If you need a stateful service, there are several ways to go. this is probably the simplest.
It sounds like you are doing this for learning purposes, in which case I suggest reading up on why it is not a good practice to develop using stateful services. Try this one for starters.
Since web services are stateless you can't do what you are trying to do.
Although you have only one client instance, for each call a server-side instance gets created. That means that in the first call you set the variable on an object, which then goes out of scope (since it's tied to that request). When you do make the second call, a new instance of your service gets created and this new instance obviously has no knowledge of the previous one.
If you want to do something like that you need the save the state. This can be done in various ways:
Save the value in the Application object (HttpContext.Current.Application("myvar") = a)
Save it in session state (you need to add an attribute to the service class to enable session state, then you do the same as with the Application but accessing HttpContext.Current.Session
Save it in a database
Save it in a file
...
#I4V - Thanks for your comment on my post.
I just added static before the bool variables and it worked.
I am having some trouble implementing the right patterns for a work project and I don't want to precede until I am satisfied with the right design strategy.
The project is based around Genesys Computer Telephony Integration (CTI) Platform. Essentially, utilizing a SDK provided by Genesys, a single client subscribes to a number of Genesys services (or TServers) running remotely. The client then registers a whole heap of Directory Numbers (DN's) associated to a particular TServer and waits for call events. When an event occurs, it is captured by the client and stored in a database. A number of other operations are executed, which is irrelevant at this stage. A lot of the communication work is handled by the Genesys ProtocolManager object, so a single event handler captures event data across all clients, which in turn is handled by a EventBrokerService. Here is a simple code to illustrate the connection process, registration of a single DN and the event function:
EventBrokerService eventBrokerService;
using (var client = new TServerProtocol(
new Endpoint(
new Uri("tcp://tserver01:11234"))))
{
client.Open();
eventBrokerService = BrokerServiceFactory.CreateEventBroker(client);
eventBrokerService.Activate();
eventBrokerService.Register(this.OnEvent);
RequestRegisterAddress requestRegisterAddress =
RequestRegisterAddress.Create("977845873",
RegisterMode.ModeMonitor,
ControlMode.RegisterDefault,
AddressType.DN);
IMessage response = client.Request(requestRegisterAddress);
}
and then we listen for events (there are many different events):
private void OnEvent(IMessage response)
{
switch (response.Id)
{
case EventACK.MessageId:
//do something
break;
case EventLinkConnected.MessageId:
var ev = response as EventLinkConnected;
//Insert event into DB and perform some other operations...
break;
}
}
The Genesys Platform, comes with another component called a Genesys Configuration server. The config server holds all of the TServer details, including the DN information and a whole bunch of other "objects". It is really just a fancy DBMS. The difference is, you can also subscribe to the config server and register for CRUD events (i.e. CreateEvent, UpdateEvent etc...). Without illustrating the code, the concept is similar to the one above. (i.e. You can register to a number of different Configuration Servers and listen for CRUD events).
For the most part, I have covered the above well and I am satisfied with the implementation so far. What I am trying to achieve is as follows:
I am attempting to implement a distributed system. In a nutshell, the system will consist of 2 components. Monitoring Services and Dispatcher Service components (they will all be Windows Services)
Monitoring Service Component
The "Monitoring Service(s)" connect to 1 or many T Servers to monitor for call events
The monitoring service will ALSO subscribe to a dispatcher service
Dispatcher Service Component
The "Dispatcher Service" connects to 1 or more Configuration Servers and waits for CRUD events.
Once an event occurs (i.e. a new DN was added on the config server), the dispatcher captures the creation event, and notifies all monitoring service subscribers. Subsequently, the dispatcher will also update a local database, so the DN information is preserved for redundancy (in case dispatcher can not connect to a Configuration Server).
The monitoring subscriber, to whom the newly created DN belongs (distinguished by a unique DBID and TServerID identifiers) will accept the DN, and register it for listening events (similarly illustrated in the first code snippet). The monitoring subscriber who does not possess the required TServer connection will drop the received request, naturally.
The Dispatcher can also receive newly added TServers, but this time around, it will make the decision which monitoring service it want's to utilize in order for that monitoring service to make ANOTHER connection. This will be determined by factors such as the number of current sessions running on a monitoring service or the how much memory a single service is chewing up at the time.
I have come up with some basic concepts and here is some of the code to illustrate what I have done thus far:
The communication method I have chosen is WCF with NetTcpBinding, so for the simple part, I have exposed an interface:
[ServiceContract(Namespace = "urn:Netwatch",
SessionMode = SessionMode.Required,
CallbackContract = typeof(IDisMonServiceCallback))]
public interface IDisMonService
{
[OperationContract]
bool Subscribe(string uid);
[OperationContract(IsOneWay = true)]
void Unsubscribe(string uid);
}
[ServiceContract(Namespace="urn:Netwatch")]
public interface IDisMonServiceCallback
{
[OperationContract]
bool DNRegistered(int tServerId, string dnEntry);
}
and on the dispatcher, I have implemented it:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class DisMonService : IDisMonService
{
private ConcurrentDictionary<string, IDisMonServiceCallback> subscribers = new ConcurrentDictionary<string, IDisMonServiceCallback>();
public IDisMonServiceCallback this[string uid]
{
get
{
IDisMonServiceCallback callback;
if (!subscribers.TryGetValue(uid, out callback))
return null;
return callback;
}
}
public List<IDisMonServiceCallback> GetAllServiceCallbacks()
{
return new List<IDisMonServiceCallback>(subscribers.Values);
}
public bool Subscribe(string uid)
{
IDisMonServiceCallback callback = GlobalHelper.Callback<IDisMonServiceCallback>();
if (!subscribers.ContainsKey(uid))
if (!subscribers.TryAdd(uid, callback))
return false;
return true;
}
public void Unsubscribe(string uid)
{
IDisMonServiceCallback callback;
if (subscribers.ContainsKey(uid))
if (!subscribers.TryRemove(uid, out callback))
return;
return;
}
}
From the code above, it is obvious that each subscribing monitoring service has a unique identifier, that way the right service callback context is retrieved (in case I decide to do some other funky operations).
This is where my dilemma essentially begins. To cut the long story short, my question(s) are as follow:
How do I deal with DisMonService class when attempting to pass on messages to all subscribers from within the Dispatcher service. i.e. new DN has been added, let us call the DisMonService class and notify all subscribers.
What would be the most optimal pattern to implement in dealing with updates to all subscribers from within DisMonServie
At the moment my dummy client connects to the dispatcher, and it registers itself. Moving forward, what is the best way to access the DisMonService class.
I hope I am not confusing anybody at what I am trying to ask. I guess what I am really trying to find is best way to implement the above system, any suggestions and such. Some code samples and snippets would really be helpful.
This is my first post here so I apologise to anybody if I haven't explained myself to the forum's standards.
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.