Update an ASP.NET page with Duplex WCF Service Call Result - c#

I am having a problem to design the best way for invoking a duplex WCF service from ASP.NET Application I have the following scenario:
1) I have a duplex WCF service with some operations
2) From an ASP.NET web application (which is my client) I make the default page implement the callback Interface and then call a method from the duplex service sending itself as the handler of the callback
3) When the callback returns on the default.aspx page I couldn't show the result on the page because the whole HttpContext is null so I can't access any control or Application[] or Session[] variables
Here is the code in the Default.aspx
[CallbackBehavior(UseSynchronizationContext = false)]
public partial class _Default : System.Web.UI.Page, VehicleTrackingService.IDuplexServiceCallback
{
public _Default()
{
}
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
{
try
{
DuplexService client = new DuplexServiceClient(new InstanceContext(new_Default()));
switch (DropDownList1.SelectedItem.Value)
{
case "0":
{
client.Method1(int.Parse(txt_name.Text));
break;
}
case "1":
{
lbl_res.Text = "Not Provided yet.";
break;
}
default:
{
lbl_res.Text = "Not Provided yet.";
break;
}
}
}
catch(Exception ex)
{
}
}));
}
public void DuplexCallbackFunction(string response)
{
// Wanna to show result (the response) from here ...
}
Any Help Please?

You are calling the WCF service from the ASP.Net page while the page is being processed on the server.
The problem with this is that the page is on the server for a very short time, purhaps less than a second. Then the page has been returned to the browser before the WCF service has responded.
As Lloyd mentioned the way to fix this is to call the web service from your browser using AJAX.
For one example of how to do this see http://www.codeproject.com/Articles/128478/Consuming-WCF-REST-Services-Using-jQuery-AJAX-Call

You have to keep in mind that your application consists of a browser client that is accessing the ASP.NET application as a server, and these two communicate via HTTP requests and responses. Your ASP.NET application will most likely have sent an HTTP response back to the browser before the WCF service sends a message back to the ASP.NET application.
I think Shiraz and Lloyd have made an excellent suggestion; try to call the WCF service directly from the browser, if possible. This answer suggests that it may be possible to perform duplex communication with a WCF service with JavaScript.
However, there may be a number of reasons why you can't do that, such as credentials, network firewall rules, or simply the fact that the ASP.NET application has the necessary data to make the call to the WCF service, and perhaps you don't want to expose that data to the browser.
In these cases, you can choose to implement complicated solutions that involve using JavaScript in the browser to poll the ASP.NET server for updates. There are a couple of ways to do this. There is "short polling" and "long polling". There is also a relatively new feature called WebSockets, but whether or not your server and your target browser supports WebSockets is another question.

Related

Recording events(request & response) in an MVC application

Ok, so I have quite a task here:
The background of this project is very complex and fully covered by NDA's so I'll just state what I am trying to do without the background.
So what I need is a way to record every request made to an MVC application and every response from it.
Furthermore, I also need a way to "reply" the requests exactly as they were sent.
I was hoping that I could create some solution that "loads" the MVC application, Self hosts or runs in IIS, get requests, records them and passed them verbatim to the MVC application which would then act exactly like any other MVC app.
I could then create a second solution that "loads" the MVC app but instead of opening it up to request it would read the events from the event store and "replays" them in the MVC app.
Now I have no clue where to even start. This kinda thing is way out of my comfort zone.
If there is another solution for how I can record and replay request (and responses) then please let me know.
Even if there is a way to intercept a request in MVC before it starts doing all of its authentication and routing malarkey then that would be a great starting point. I would also need to know where I can capture the response at the very last second before it is sent.
Many thanks for your time
Andy
A HttpModule would work just fine for your scenario:
using System;
using System.Web;
public class HelloWorldModule : IHttpModule
{
public HelloWorldModule()
{
}
public String ModuleName
{
get { return "HelloWorldModule"; }
}
// In the Init function, register for HttpApplication
// events by adding your handlers.
public void Init(HttpApplication application)
{
application.BeginRequest +=
(new EventHandler(this.Application_BeginRequest));
application.EndRequest +=
(new EventHandler(this.Application_EndRequest));
}
private void Application_BeginRequest(Object source,
EventArgs e)
{
// Create HttpApplication and HttpContext objects to access
// request and response properties.
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
/*...*/
}
private void Application_EndRequest(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
/*...*/
}
public void Dispose() { }
}
The code and more information available here.

Trying to start a SignalR connection from an ASP.NET Core action call gives TypeLoadException

The setup I'm trying to accomplish is this: I have a signalR server that supports 2 types of clients - one type that supplies data and another that receives data. When a "receiver" type client chooses one of the "sender" type clients to monitor, the SignalR server makes a call to the "sender" client to open a connection. The "sender" client is an ASP.NET Core instance running as a Windows Service. The POST request calls a service that starts a timer and tries to open a SignalR connection as a client. The POST request is going through as expected and it calls the service properly. When the service tries to open the SignalR connection, though, I get: System.TypeLoadException in SignalR.Client.dll (Inheritance security rules violated by type: 'System.Net.Http.WebRequestHandler'. Derived types must either match the security accessibility of the base type or be less accessible).
The action method in the controller looks like this:
[HttpPost]
public IActionResult StartUpdate()
{
_updateDriver.StartTiming();
return Ok("Timing has started");
}
And the method in the service looks like this:
public void StartTiming()
{
if (!_isTiming)
{
try
{
_hubProxy = _hubConnection.CreateHubProxy("RemoteDataServerHub");
_hubConnection.Start().Wait();
_hubProxy.Invoke("JoinGroup", "Sender").Wait();
_timer.Start();
_isTiming = true;
}
catch (Exception ex)
{
Debug.Print(ex.Message);
_isTiming = false;
}
}
}
The exception is thrown on the _hubConnection.Start().Wait() line. Does anyone have any idea what's going on here? I'm not very experienced in web applications or ASP.NET Core or SignalR. I may be biting off a bit more than I can chew here. But if anyone can point me in the right direction, it would be much appreciated!
Thanks!

Multithreaded web service calls in asp.net web forms

I have an aspx page to make calls to a web service, each of which can take up to few minutes and I want to make it work in a multi-threaded way. Basically what I want is when user clicks one of the buttons
I want to make a service call to my web service but I also want user to be able to click the other buttons and make other service calls if they want. and if the later calls
are completed faster than the first one, results must be shown to user without waiting for the result of the first call. (Yo can think about desktop sql editor applications)
However I can't manage this with my current method. The first call always blocks the following ones, I wonder If I can accomplish this
kind of behviour in a web application.
I use a code like the floowing for my service calls:
protected void GetResult_Click(object sender, EventArgs e)
{
ShowSelectData(sql, connStr, tabId);
}
private void ShowSelectData(string sql, string connStr, string tabId)
{
SqlServiceClient cli = new SqlServiceClient();
cli.ShowSelectDataCompleted += cli_ShowSelectDataCompleted;
cli.ShowSelectDataAsync(sql, connStr, tabId);
}
void cli_ShowSelectDataCompleted(object sender, SqlService.ShowSelectDataCompletedEventArgs e)
{
var res = e.Result;
//here I show resullts to user
}
I also add Async="true" to my aspx page
Basically what I want is when user clicks one of the buttons I want to
make a service call to my web service but I also want user to be able
to click the other buttons and make other service calls
What you asked can be accomplished by ajax async call; leave to your client the burden to call the service (by an async call) and manage the response.
When the user click a button make a call to the service; meantime the first call is executing the client can call the second, meantime first and second are executing the client can call the third... the user is not frozen waiting the first call to finish
If you can't call the service directly from a javascript client wrap server side the service calls into rest services and call the rest services from your client.

How to remove a timer, after a session ends?

I'm implementing an auto-refresh feature on a asp.net website.
The user does the login on the website, and if he goes to a specific page, which has a table that needs to be refreshed, a timer is created that refreshes the table.
But when the user logs out or the session expires, the timer keeps running. Now multiply this for X users, and we will have X timers running on the server.
What's the best way to get rid of the timers when they're no longer needed?
So far my code is the following:
protected static System.Timers.Timer _timer;
protected void Page_Load(object sender, EventArgs e)
{
...
ServiceStatus serv = new ServiceStatus();
OutSubscricoesInfoV2 subscr = new OutSubscricoesInfoV2();
serv = StreamerUtils.GetSubscricoesStreamer(ref subscr);
if (serv != null && serv.success)
{
StreamerUtils.StreamerState strState = StreamerUtils.GetStreamerState(subscr);
if (strState != null && strState.IsActive)
{
startAutoRefresh();
}
}
}
private void startAutoRefresh()
{
if (Session["RefreshTimer"] == null)
{
_timer = new System.Timers.Timer(10000);
_timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
_timer.Enabled = true;
Session["RefreshTimer"] = _timer;
}
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
//TODO: call refresh function
}
In my page, i have the following button which the user can click to refresh the table:
<asp:ImageButton runat="server" ID="RefreshCot" OnClientClick="javascript:StocksListControl.TriggerPostBack(); return false;" CausesValidation="false" ImageUrl="/_layouts/images/refresh-title.png" />
I agree with the first comment to your question posted by Aristos, this is bad design.
For this situation I would suggest three options:
Use a asp.net Ajax control. An example can be found here: http://www.tutorialspoint.com/asp.net/asp.net_ajax_control.htm
AJAX poling - Have the timers in JavaScript which will sit on the clients. Once the timer has passed its elapsed time, the client will make an AJAX request to the server (preferably calling a web service) to fetch the updated data. I would recommend using a JavaScript library for this such as JQuery. The documentation on their ajax function is found here:
http://api.jquery.com/jQuery.ajax/
Consider using a library that provides real time functionality such as SignalR, here is a link to the libraries site:
http://signalr.net/
Now for the personal opinions; Of all 3 options, the 3rd will provide you with the most "elegant" solution.
The 1st option will require you to use asp.net AJAX controls, which produce ugly HTML and can be a pig to work with. Also, timers on the client will be created which remove the true "real-time" aspects.
The 2nd option will again put timers on the client, removing the true "real-time" aspects.
The 3rd option, will allow the server to be "aware" of connected clients, data shall be pushed to the clients, when available, via the use of "Hubs".
Whilst your'e at this learning curve crossroad, I would also recommend looking into some client side JavaScript design patterns to help structure your code on the clients. A great tool to use could be Knockout, found here:
http://knockoutjs.com/index.html
Here is a tutorial on how to use this with SignalR:
http://www.codeproject.com/Articles/322154/ASP-NET-MVC-SIngalR-and-Knockout-based-Real-time-U
The tutorial focuses on using ASP.NET MVC. I imagine this should be interchangeable with web forms, however, if the option is available to you I would recommend using MVC also.

How to communicate Server to Client with SignalR in Nancy with ASP.NET Hosting?

Most of the examples I've found for SignalR are assuming ASP.NET (MVC or not). I'm using NancyFX. I'm having just one problem, so I'm hoping there's something I'm overlooking or some thing I need to do in Nancy to compensate for not being ASP.NET.
My one goal is to be able to notify the client browsers when a server event happens. I don't plan on replacing my Nancy routes with hub methods. But I would like the ability to call into the browser from my routes (actions).
I have very simple Hub that I created following the example in the SignalR Wiki. I'm not even sure I need it, since I don't plan on calling client to server.
public interface IUserNotifier
{
void Start();
void Notify(object #event);
}
I used an interface in hopes that I would be able to inject the same hub later on to use in my nancy routes... I'm not sure that is in the cards.
[HubName("userNotifier")]
public class UserNotifier : Hub, IUserNotifier
{
public void Start()
{
Notify(new {Status = "Started"});
}
public void Notify(object #event)
{
Clients.notification(#event);
}
}
When I have the following code in my html file, I can see that it executes the Start() method, and then the Notify() method, delivering content to my client.
var communicator = $.connection.userNotifier;
$.extend(communicator, {
Notification: function(event) {
alert("notification received from server!");
console.log(event);
}
});
$.connection.hub.start()
.done(function() {
communicator.start();
});
Like I said, "starting" the hub works and sends a notification to the client. Very cool. But, then, my primary goal hasn't been accomplished yet. I need to initiate these notifications from other places in my code where they might not be directly associated with a "request".
I tried injecting my IUserNotifier in my nancy modules for use in the routes, but when the Notify() is fired, I get:
That's because the Clients property on the Hub base class is null (hasn't been initialized). So, I switched gears. I tried to follow multiple examples, including the example from the wiki page about hubs in the section called "Broadcasting over a Hub from outside of a Hub":
public class NotifierModule : NancyModule
{
public NotifierModule(){
Get["/notify/{message}"] = p => {
var context = GlobalHost.ConnectionManager.GetHubContext<UserNotifier>();
context.Clients.notification(new { Message = p.message });
};
}
}
My Nancy route executes without throwing errors. Except my browser never receives the message. If I set a breakpoint in the route, I can see that Clients is initialized. Maybe the collection of clients is initialized but empty. Who knows? Maybe you do. :)
Again, my main goal is to be able to send events/notifications to the browser from anywhere in my code, any time. Is that too much to ask? What should I be doing here?
I'm sure you must have found the answer already. However, I figured I could try and help out in case anyone else runs into a similar problem. In order for your server on the .NET side to send messages to clients, it would also need to have a connection made to the hub.
var connection = new HubConnection("http://localhost/");
connection.Start();
connection.Notify("Hello");
Check out an official example at:
https://github.com/SignalR/SignalR/blob/master/samples/Microsoft.AspNet.SignalR.Client.Samples/Program.cs

Categories

Resources