I want to implement all types error Handling for web socket implementation at server side.
My Server Side Code
public class WebSocketManager : WebSocketHandler
{
public override void OnOpen()
{
// Do when Connection Is Open
}
public override void OnClose()
{
// Close Connection
}
public override void OnMessage(string message)
{
// When Any Message Sent to Client
}
}
You can add exception handling using try catch blocks and log the errors to a log file. Like this:
http://www.codeproject.com/Articles/2344/Create-Simple-Error-Log-Files-using-ASP-NET-and-C
Or you can log them to the event viewer if you want.
Related
I have a remote computer with Redis. From time to time new entries are added to it (key-value pair). I want Redis to send notifications to my C# Service about events like this (i'm interested in value part). I've searched online and found simple code example to subscribe my Service to Redis. How to make Redis send notifications?
Service:
public partial class ResultsService : ServiceBase
{
private ConnectionMultiplexer connection = ConnectionMultiplexer.Connect(ConfigurationManager.AppSettings["RedisConnection"]);
private const string ChatChannel = "__keyspace#0__:*";
public VerificationResultsService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Start();
}
public void Start()
{
var pubsub = connection.GetSubscriber();
pubsub.Subscribe(ChatChannel, (channel, message) => MessageAction(message));
while (true)
{
}
}
private static void MessageAction(RedisValue message)
{
// some handler...
}
}
Making redis send automatic keyspace notifications is a redis server configuration piece, which can be enabled via the .conf file (notify-keyspace-events), or via CONFIG SET at runtime; the documentation for this is here.
You can see how this works with example code:
using StackExchange.Redis;
using System;
using System.Linq;
static class P
{
private const string ChatChannel = "__keyspace#0__:*";
static void Main()
{
// connect (allowAdmin just lets me use ConfigSet)
using var muxer = ConnectionMultiplexer.Connect("127.0.0.1,allowAdmin=true");
// turn on all notifications; note that this is server-wide
// and is NOT just specific to our connection/code
muxer.GetServer(muxer.GetEndPoints().Single())
.ConfigSet("notify-keyspace-events", "KEA"); // KEA=everything
// subscribe to the event
muxer.GetSubscriber().Subscribe(ChatChannel,
(channel, message) => Console.WriteLine($"received {message} on {channel}"));
// stop the client from exiting
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
which works like:
However, in many scenarios you may find that this is too "noisy", and you may prefer to use either a custom named event that you publish manually when you do things that need notification, or (again manually) you could make use of the streams features to consume a flow of data (streams can be treated as a flow of events in the "things that happened" sense, but they are not delivered via pub/sub).
I use the SignalR 1.0.
When exception occurs on the server, the client gets a message like this
{"I":"0","E":"Exception of type 'System.Exception' was thrown.","T":" at METHODNAME in d:\PATH\TO\HUB.cs:line 227\r\n at METHODNAME in d:\PATH\TO\HUB.cs:line 51"}
But I want to make it more user-friendly. How to I can do it?
I have read a suggestion to put all server methods into try-catch block. But I think that it is not a true-way.
I traced the Exception and found that the Exception was catched in the Microsoft.AspNet.SignalR.Hubs.HubDispatcher.Incoming method. But it is internal static method which I cannot customize.
In the ideal case I want to get ability to convert an exception to a valid response.
You can use a HubPipelineModule.
For example:
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Hubs;
public class MyHubPipelineModule : HubPipelineModule
{
protected override Func<IHubIncomingInvokerContext, Task<object>> BuildIncoming(Func<IHubIncomingInvokerContext, Task<object>> invoke)
{
return async context =>
{
try
{
// This is responsible for invoking every server-side Hub method in your SignalR app.
return await invoke(context);
}
catch (Exception e)
{
// If a Hub method throws, have it return the error message instead.
return e.Message;
}
};
}
}
Then in your Global.asax.cs:
protected void Application_Start()
{
GlobalHost.HubPipeline.AddModule(new MyHubPipelineModule());
//...
RouteTable.Routes.MapHubs();
}
Using C# I'd like to take control over the reading of the HTTP Requests from a POST. Primarily to read the stream of a multipart/form-data file upload to track the stream as it's received from the client.
Using the ProcessRequest or the Async BeginProcessRequest the body has already been parsed by ASP.net / IIS.
Is there a way to override the built-in reading via a HTTPHandler, or will I have to use another mechanism?
Many thanks
Andy
Update - Added code example as requested, albeit no different to a normal class that's implemented IHttpHandler
public class MyHandler : IHttpHandler
{
public bool IsReusable { get { return true; } }
public void ProcessRequest(HttpContext context)
{
// The body has already been received by the server
// at this point.
// I need a way to access the stream being passed
// from the Client directly, before the client starts
// to actually send the Body of the Request.
}
}
It appears that you can capture the stream via the context.BeginRequest event of a HttpModule.
For example :
public class Test : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(onBeginRequest);
}
public void onBeginRequest(object sender, EventArgs e)
{
HttpContext context = (sender as HttpApplication).Context;
if( context == nul ) { return; }
if (context.Request.RawUrl.Contains("test-handler.ext"))
{
Logger.SysLog("onBeginRequest");
TestRead(context);
}
}
// Read the stream
private static void TestRead(HttpContext context)
{
using (StreamReader reader = new StreamReader(context.Request.GetBufferlessInputStream()))
{
Logger.SysLog("Start Read");
reader.ReadToEnd();
Logger.SysLog("Read Completed");
}
}
}
Really I was trying to avoid HttpModules, as they are processed for every .net request, so really I'd stil like to know how to do it via a HTTPHandler.
You can definitely do that by implementing an IHttpHandler.
This example will get you started. There is no need to override the built-in reading.
You receive all the data in the Request, and can process it as required.
I'm creating an attribute so that whenever an exception occurs on my site, I'll receive an email detailing the exception. I've got so far but my Attribute code doesn't seem to fire if an exception occurs:
public class ReportingAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
// This will generate an email to me
ErrorReporting.GenerateEmail(filterContext.Exception);
}
}
Then above my Controller I'm doing:
[ReportingAttribute]
public class AccountController : Controller
The other way to do it is ofcourse putting ErrorReporting.GenerateEmail(ex) inside my catch blocks? There must be a simpler way? Thats why I thought of creating the Attribute to handle this
For the purpose of logging all uncaught exceptions, you can define the following method in your Global.asax.cs file:
private void Application_Error(object sender, EventArgs e)
{
try
{
//
// Try to be as "defensive" as possible, to ensure gathering of max. amount of info.
//
HttpApplication app = (HttpApplication) sender;
if(null != app.Context)
{
HttpContext context = app.Context;
if(null != context.AllErrors)
{
foreach(Exception ex in context.AllErrors)
{
// Log the **ex** or send it via mail.
}
}
context.ClearError();
context.Server.Transfer("~/YourErrorPage");
}
}
catch
{
HttpContext.Current.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
}
Attribute just by itself can not define a behaviour, but its used for make some marks over your code data. You should write a code, where you
get an exception
check for given attribute presence in the method that raised an exception
if it is present, collect and send the data you need.
Why not create an base controller:
public ApplicationBaseController : Controller
{
public override void OnException(ExceptionContext context)
{
//Send your e-mail
}
}
And derive your controller from ApplicationBaseController
public HomeController : ApplicationBaseController
{
//.....
}
I'm tring to implement my first WCF call-back server. This is my code:
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ILogCallback))]
public interface ILog
{
}
public interface ILogCallback
{
[OperationContract(IsOneWay = true)]
void Push(string callbackValue);
}
public class MyLog : ILog
{
}
class Log
{
public static void initialize()
{
using (ServiceHost host = new ServiceHost(
typeof (MyLog),
new Uri[]
{
new Uri("net.pipe://localhost")
}))
{
host.AddServiceEndpoint(typeof (ILog),
new NetNamedPipeBinding(),
"PipeReverse");
host.Open();
// TODO: host.Close();
}
}
public static void Push(string s)
{
ILogCallback callbacks = OperationContext.Current.GetCallbackChannel<ILogCallback>();
callbacks.Push(s);
}
}
then I try to use my server using this code:
Log.initialize();
while (true)
{
Log.Push("Hello");
System.Threading.Thread.Sleep(1000);
}
But I got NPE, because OperationContext.Current is null. Why, what's wrong and how to fix that?
Because you are NOT in the context of an operation.
You're simply calling a static method of the Log class.
For you to be in an Operation Context your call MUST have been come from a client that is being serviced by your WCF server.
OperationContext.Current is a thread-static property that is initialized when request arrives to the server. Here's what you do to call the callback
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ILogCallback))]
public interface ILog
{
void PushOnTheClient();
}
public class MyLog : ILog
{
void PushOnTheClient()
{
ILogCallback callbacks = OperationContext.Current.GetCallbackChannel<ILogCallback>();
callbacks.Push(s);
}
}
You are missing the subscriber's subscription. The way you do this is to create a [oneway] operation in your MyLog WCF server called something like: "void SendMeLogs()".
This will open the client callback channel. You Then have to implement SendMeLogs() in lines of something like:
void SendMeLogs()
{
while(CheckLogsForNewData())
{
PushOnTheClient();
}
}
Since the SendMeLogs() function is oneway, the client will not block, but will start the subscription to your log server. (you can search the net for sample code for duplex calculator in wcf for a good example of this architecture).
The key however is that you must have a nice unsubscribe method like "StopSendingMeLogs" to break the loop, and also make the PushOnTheClient function fail safe, in case the client terminates or the specific client connection goes down.
The "CheckLogsForNewData" function should ideally be a shared (static) implementation in your case