I need to create an C# application that will monitor whether a set of web services are up and running. User will select a service name from a dropdown. The program need to test with the corresponding service URL and show whether the service is running. What is the best way to do it? One way I am thinking of is to test whether we are able to download the wsdl. IS there a better way?
Note: The purpose of this application is that the user need to know only the service name. He need not remember/store the corresponding URL of the service.
I need a website version and a desktop application version of this C# application.
Note: Existing services are using WCF. But in future a non-WCF service may get added.
Note: My program will not be aware of (or not interested in ) operations in the service. So I cannot call a service operation.
REFERENCE
How to check if a web service is up and running without using ping?
C program-How do I check if a web service is running
this would not guarantee functionality, but at least you could check connectivity to a URL:
var url = "http://url.to.che.ck/serviceEndpoint.svc";
try
{
var myRequest = (HttpWebRequest)WebRequest.Create(url);
var response = (HttpWebResponse)myRequest.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
// it's at least in some way responsive
// but may be internally broken
// as you could find out if you called one of the methods for real
Debug.Write(string.Format("{0} Available", url));
}
else
{
// well, at least it returned...
Debug.Write(string.Format("{0} Returned, but with status: {1}",
url, response.StatusDescription));
}
}
catch (Exception ex)
{
// not available at all, for some reason
Debug.Write(string.Format("{0} unavailable: {1}", url, ex.Message));
}
This approach works for me.
I used Socket to check if the process can connect.
HttpWebRequest works if you try to check the connection 1-3 times but if you have a process which will run 24hours and from time to time needs to check the webserver availability that will not work anymore because will throw TimeOut Exception.
Socket socket
= new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var result = socket.BeginConnect("xxx.com", 80, null, null);
// test the connection for 3 seconds
bool success = result.AsyncWaitHandle.WaitOne(3000,false);
var resturnVal = socket.Connected;
if (socket.Connected)
socket.Disconnect(true);
socket.Dispose();
return resturnVal;
Related
I'm developing an application that hosts a browser control. The client (in the browser, using a localhost address) communicates with the server via websockets and the server handles the Http requests.
The users can define ports for both Http and Ws, but (since several instances of the application can be opened) I need to detect, if they are usable - if not, I notify the users that an alternative port will be used.
Verifying that the intended Http port is blocked was possible using a HttpListener, but (for reasons I don't understand) the listener could apparently use a port already used by another application for a websocket connection.
So I ended up with the following code, which appears to do the job. I use it to first test a specified port and, if that fails, I loop through a range of port numbers and try until the method returns True.
private static bool testPort(int port)
{
bool result = false;
System.Net.IPEndPoint endpoint = new System.Net.IPEndPoint(System.Net.IPAddress.Loopback, port);
using (System.Net.Sockets.Socket s = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP)) {
try {
Console.WriteLine("Testing port {0}", port);
s.Connect(endpoint);
s.Bind(endpoint);
result = true;
} catch (SocketException ex) {
switch (ex.SocketErrorCode) {
case SocketError.InvalidArgument:
//This error is apparently thrown when a port is occupied.
result = false;
break;
case SocketError.ConnectionRefused:
//NOTE: This error is apparently thrown when a port is not occupied (but the connection fails, because the socket cannot connect since the port is not being used?).
result = true;
break;
default:
result = false;
break;
}
} catch (Exception ex) {
result = false;
}
}
return result;
}
But I'm not sure, if maybe it's just a "lucky coincidence". Like I mentioned, it works as far as I could test it, but does it make any sense? And: is it reliable?
The code is subject to a race condition. The connect call might fail because the port is not in use, but another program may then take that port before the function is able to return.
Testing a bunch of ports could result in noticeable delays as well. For example a firewall may be configured to drop packets rather than sending a connection refused response. In this case the connect call would block until a timeout is reached.
As a side note, Bind needs to be called before Connect to work, however in this case the Bind call should be removed. You cannot bind a connecting socket to the same endpoint you're attempting to connect to.
Using Visual studio 2012, C#.net 4.5 , SQL Server 2008, Feefo, Nopcommerce
Hey guys I have Recently implemented a new review service into a current site we have.
When the change went live the first day all worked fine.
Since then though the sending of sales to Feefo hasnt been working, There are no logs either of anything going wrong.
In the OrderProcessingService.cs in Nop Commerce's Service, i call a HttpWebrequest when an order has been confirmed as completed. Here is the code.
var email = HttpUtility.UrlEncode(order.Customer.Email.ToString());
var name = HttpUtility.UrlEncode(order.Customer.GetFullName().ToString());
var description = HttpUtility.UrlEncode(productVariant.ProductVariant.Product.MetaDescription != null ? productVariant.ProductVariant.Product.MetaDescription.ToString() : "product");
var orderRef = HttpUtility.UrlEncode(order.Id.ToString());
var productLink = HttpUtility.UrlEncode(string.Format("myurl/p/{0}/{1}", productVariant.ProductVariant.ProductId, productVariant.ProductVariant.Name.Replace(" ", "-")));
string itemRef = "";
try
{
itemRef = HttpUtility.UrlEncode(productVariant.ProductVariant.ProductId.ToString());
}
catch
{
itemRef = "0";
}
var url = string.Format("feefo Url",
login, password,email,name,description,orderRef,productLink,itemRef);
var request = (HttpWebRequest)WebRequest.Create(url);
request.KeepAlive = false;
request.Timeout = 5000;
request.Proxy = null;
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.StatusDescription == "OK")
{
var stream = response.GetResponseStream();
if(stream != null)
{
using (var reader = new StreamReader(stream))
{
var content = reader.ReadToEnd();
}
}
}
}
So as you can see its a simple webrequest that is processed on an order, and all product variants are sent to feefo.
Now:
this hasnt been happening all week since the 15th (day of the
implementation)
the site has been grinding to a halt recently.
The stream and reader in the the var content is there for debugging.
Im wondering does the code redflag anything to you that could relate to the process of website?
Also note i have run some SQL statements to see if there is any deadlocks or large escalations, so far seems fine, Logs have also been fine just the usual logging of Bots.
Any help would be much appreciated!
EDIT: also note that this code is in a method that is called and wrapped in A try catch
UPDATE: well forget about the "not sending", thats because i was just told my code was rolled back last week
A call to another web site while processing the order can degrade performance, as you are calling to a site that you do not control. You don't know how much time it is going to take. Furthermore, the GetResponse method can throw an exception, if you don't log anything in your outer try/catch block then you won't be able to know what's happening.
The best way to perform such a task is to implement something like the "Send Emails" scheduled task, and send data when you can afford to wait for the remote service. It is easy if you try. It is more resilient and easier to maintain if you upgrade the nopCommerce code base.
This is how I do similar things:
Avoid modifying the OrderProcessingService: Create a custom service or plugin that consumes the OrderPlacedEvent or the OrderPaidEvent (just implement the IConsumer<OrderPaidEvent> or IConsumer<OrderPlacedEvent> interface).
Do not call to a third party service directly while processing the request if you don't need the response at that moment. It will only delay your process. At the service created in step 1, store data and send it to Feefo later. You can store data to database or use an static collection if you don't mind losing pending data when restarting the site (that could be ok for statistical data for instance).
Best way to implement point #2 is to add a new scheduled task implementing ITask (remember to add a record to the ScheduleTask table). Just recover the stored data do your processing.
Add some logging. It is easy, just get an ILogger instance and call Insert.
As far as I can see, you are making a blocking synchronous call to other websites, which will definitely slow down your site in between the request-response process. What Marco has suggested is valid, try to do it in an ITask. Or you can use an asynchronous web request to potentially remove the block, if you need things done immediately instead of scheduled. :)
I have an ASP.NET 3.5 app using WebForms, currently it is being hosted on IIS6. Everything behaves great.
However, after switching to a Windows 2012 server with IIS8 installed, we intermittently get truncated requests. The majority of the time this manifests in a viewstate exception in our event log, however, on forms that do not have ViewState, we get incomplete posts (the last few fields are missing / partially truncated).
This became so problematic that we escalated to Microsoft support, and after weeks of debugging, they said that this is the "correct" behavior for II7 and above. Their explanation was the change in the IIS pipeline from 6 to 7.
IIS6 and below would buffer the entire request before passing it along to Asp.net, truncated requests would be ignored.
IIS7 and above would send the request to Asp.net after the initial headers were sent, it would be up to the app to handle truncated requests.
This becomes problematic when either there are connectivity issues (the user unplugs their cable during tranmission) or when the user presses stop / reloads the page during a post.
In our HTTP logs, we see "connection_dropped" messages that correlate to the truncated requests.
I am having trouble believing that this behavior is intended, but we have tested on a few different servers and get the same results with IIS7 and above (Windows 2008, 2008 R2, and 2012).
My questions are:
1) Does this behavior even make sense?
2) If this is "correct" behavior, how do you protect your app against potentially processing incomplete data?
3) Why is it the application developer's responsibility to detect incomplete requests? Hypothetically, why would the app developer handle the incomplete request other than ignoring it?
Update
I wrote a small asp.net application and website to demonstrate the issue.
Server
Handler.ashx.cs
public class Handler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.Request.HttpMethod == "POST")
{
var lengthString = context.Request.Form["Length"];
var data = context.Request.Form["Data"];
if (lengthString == null)
{
throw new Exception("Missing field: Length");
}
if (data == null)
{
throw new Exception("Missing field: Data");
}
var expectedLength = int.Parse(lengthString);
if (data.Length != expectedLength)
{
throw new Exception(string.Format("Length expected: {0}, actual: {1}, difference: {2}", expectedLength, data.Length, expectedLength - data.Length));
}
}
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World, Request.HttpMethod=" + context.Request.HttpMethod);
}
public bool IsReusable
{
get { return false; }
}
}
Client
Program.cs
static void Main(string[] args)
{
var uri = new Uri("http://localhost/TestSite/Handler.ashx");
var data = new string('a', 1024*1024); // 1mb
var payload = Encoding.UTF8.GetBytes(string.Format("Length={0}&Data={1}", data.length, data));
// send request truncated by 256 bytes
// my assumption here is that the Handler.ashx should not try and handle such a request
Post(uri, payload, 256);
}
private static void Post(Uri uri, byte[] payload, int bytesToTruncate)
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
// this allows us to disconnect unexpectedly
LingerState = new LingerOption(true, 0)
};
socket.Connect(uri.Host, uri.Port);
SendRequest(socket, uri, payload, bytesToTruncate);
socket.Close();
}
private static void SendRequest(Socket socket, Uri uri, byte[] payload, int bytesToTruncate)
{
var headers = CreateHeaders(uri, payload.Length);
SendHeaders(socket, headers);
SendBody(socket, payload, Math.Max(payload.Length - bytesToTruncate, 0));
}
private static string CreateHeaders(Uri uri, int contentLength)
{
var headers = new StringBuilder();
headers.AppendLine(string.Format("POST {0} HTTP/1.1", uri.PathAndQuery));
headers.AppendLine(string.Format("Host: {0}", uri.Host));
headers.AppendLine("Content-Type: application/x-www-form-urlencoded");
headers.AppendLine("User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/99.0");
headers.AppendLine("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
headers.AppendLine("Connection: Close");
headers.AppendLine(string.Format("Content-Length: {0}", contentLength));
return headers.ToString();
}
private static void SendHeaders(Socket socket, string headers)
{
socket.Send(Encoding.ASCII.GetBytes(headers));
socket.Send(Encoding.ASCII.GetBytes("\n"));
}
private static void SendBody(Socket socket, byte[] payload, int numBytesToSend)
{
socket.Send(payload, 0, numBytesToSend, SocketFlags.None);
}
1) If you're running pipeline for the app pool to which your 3.5 application is assigned in Integrated mode, you might have trouble with how your requests are handled due to ISAPI behavior. You may be generating requests it doesn't understand properly and it then truncates them to a default value. Have you tried running the app pool in Classic mode?
2) Functional testing. Lots and lots of functional testing. Create a test harness and make all the calls your application can make to make sure it's working properly. This is not a 100% solution, but nothing really is. There are many computer science papers explaining why it's impossible to test every single possible situation in which your app may run based on the Halting Problem.
3) Because you wrote the code. You should not have incomplete requests because the request might be for an important piece of data and you need to send back an error saying that there was a problem processing a request, otherwise the issuing party just sees the request as having mysteriously vanished.
The reason IIS changed its behaviour because we (developers) needed more control over request handling. In case of broken request, we had problem investigating cause of invisible requests. We need to log requests at application level for investigation & record keeping. For example, if request involves a financial transaction like credit card transaction, we need more control and we need to record every step for compliance.
IIS is a web server framework and application level data validation is not their responsibility. If request was broken, that means the input was incomplete & application level logic will decide what to do. Application must respond correct error codes and by failures. This is the reason ASP.NET mvc has model validation which allows you to validate complete input at application level.
You can use IsClientConnected to check whether the underlying socket is still connected or not.
As the web has gone more AJAX, and more mobile, and we sometimes use ping to check health of remote services, we do not necessarily conclude that broken request is an error and must be dropped. We may still want to live with broken requests. It is the choice that application level developer can make and not the IIS.
I have a webservice that gets a list from client and inserts it to database. Client has a windows service that is sending a list per 10 seconds. But there is a problem. What if it cannot reach to webservice(server). I should not lost any of the data. I decided to save data to a txt or binary if server is not reachable, and then upload them after the server starts to run. However, how can I decide whether the webservice is unavaliable. If I store the data to a file in a catch block, it will store when ever it gets an error, not only webservice unavaliable error. Any advice?
You can make an http request on the service's endpoint url and check if everything is ok :
var url = "http://....";
//OR
var url = service_object.Url;
var request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = 2000; //timeout 20 seconds
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode != HttpStatusCode.OK)
{
throw new ApplicationException(response.StatusDescription);
}
}
catch (ApplicationException ex)
{
//Do what you want here, create a file for example...
}
I'd introduce a queuing system (such as MSMQ or NServiceBus) so that the windows service only needs to place message(s) into the queue and something else (co-located with the web service) can dequeue messages and apply them (either directly or via the web service methods).
When everything is up and running, it shouldn't introduce much more overhead over your current (direct) web service call, and when the web service is down, everything just builds up in the queuing system.
I am currently working on a WinForm app to stream videos from IP camera using the RTSP protocol in C#. Everything worked fine. Part of the requirement for the app includes a function to check whether the IP camera is online or not.
So I did a ping function using the System.Net.NetworkInformation.Ping class to ping the IP camera. Say if the RTSP url of the camera is as follows rtsp://[CAMERA IP]:554/Master0-RTSP/1.0, I would only need to extract the [CAMERA IP] part and use the Ping class to see if the camera is online or not by using its IP.
Initially, it works until an issue came, say if one to enter an IP which may not be the intended IP Camera (say an IP of a computer) the ping function would still work if the entered IP of the entered device is online.
I tried to search for something like a RTSP ping but could not find one. Was hoping for any advices or opinions on this matter. Any example in C# are greatly appreciated. Thank you for your kind attention.
OPTIONS can possibly work but the standard specifies the correct way is through using theGET_PARAMETER.
RFC2326 outlines that clearly
http://www.ietf.org/rfc/rfc2326.txt
10.8 GET_PARAMETER
The GET_PARAMETER request retrieves the value of a parameter of a
presentation or stream specified in the URI. The content of the reply
and response is left to the implementation. GET_PARAMETER with no
entity body may be used to test client or server liveness ("ping").
While GET_PARAMETER may not be supported by the server there is no way to tell how that server will react to the OPTIONS request which does not even require a sessionID. Therefor it cannot be guaranteed it will keep your existing session alive.
This is clear from reading the same RFC about the OPTIONS request
10.1 OPTIONS
The behavior is equivalent to that described in [H9.2]. An OPTIONS
request may be issued at any time, e.g., if the client is about to
try a nonstandard request. It does not influence server state.
Example:
C->S: OPTIONS * RTSP/1.0
CSeq: 1
Require: implicit-play
Proxy-Require: gzipped-messages
S->C: RTSP/1.0 200 OK
CSeq: 1
Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE
Note that these are necessarily fictional features (one would hope
that we would not purposefully overlook a truly useful feature just
so that we could have a strong example in this section).
If GET_PARAMETER is not supported then you would issue a PLAY request with the SessionId of the session you want to keep alive.
This should work even if OPTIONS doesn't as PLAY honors the Session ID and if you are already playing there is no adverse effect.
For the C# RtspClient see my project # https://net7mma.codeplex.com/
And the article on CodeProject # http://www.codeproject.com/Articles/507218/Managed-Media-Aggregation-using-Rtsp-and-Rtp
Regarding RTSP in C# see this thread Using RTMP or RTSP protocol in C#
Regarding Ping ... you can implement is as DESCRIBE operation ... but pay attention do not make it too frequently, the device should be affected.
http://www.ietf.org/rfc/rfc2326.txt
Instead of ICMP ping, you might want to keep a helper RTSP session without video/audio RTP streams, checking good standing of socket connection and sending OPTIONS or DESCRIBE command on a regular basis, e.g. once a minute, in order to see if the device is responsive.
Some suggest using GET_PARAMETER instead of options, however this is inferior method. OPTIONS is mandatory, GET_PARAMETER is not. Both serve different purpose. Both have small server side execution expense. OPTIONS is clearly the better of the two.
Some servers may not support setting stream parameters and thus not support GET_PARAMETER and SET_PARAMETER.
You can use RTSPClientSharp and do something like this:
public static async Task TestRTSPConnection(string rtspAddress, string user, string password)
{
var serverUri = new Uri(rtspAddress);
var credentials = new NetworkCredential(user, password);
var connectionParameters = new ConnectionParameters(serverUri, credentials);
var cancellationTokenSource = new CancellationTokenSource();
var connectTask = ConnectAsync(connectionParameters, cancellationTokenSource.Token);
if (await Task.WhenAny(connectTask, Task.Delay(15000 /*timeout*/)) == connectTask)
{
if (!connectTask.Result)
{
logger.Warn("Connection refused - check username and password");
}
logger.Info("Connection test completed");
}
else
{
logger.Warn("Connection timed out - check username and password");
}
}
private static async Task<bool> ConnectAsync(ConnectionParameters connectionParameters, CancellationToken token)
{
try
{
using (var rtspClient = new RtspClient(connectionParameters))
{
rtspClient.FrameReceived +=
(sender, frame) => logger.Info($"New frame {frame.Timestamp}: {frame.GetType().Name}");
while (true)
{
logger.Info("Connecting...");
try
{
await rtspClient.ConnectAsync(token);
}
catch (OperationCanceledException)
{
logger.Info("Finishing test before connection could be established. Check credentials");
return false;
}
catch (RtspClientException e)
{
logger.Error($"{e.Message}: {e.InnerException?.Message}");
return false;
}
logger.Info("Connected - camera is online");
return true;
}
}
}
catch (OperationCanceledException)
{
return false;
}
}
It works for me pretty well if you just care about pinging and if the camera is online or not. Also timeout happens when credentials are incorrect. You get direct failure if port is not exposed or connection is refused.