SignalR 1.0 - send data to a specific client - c#

I want to be able to send messages to a specific client, I have working code but I cannot find a way to identify users, as on each page load/refresh the client id will change, so I cannot rely on that.
I have tried to append a querystring to the connection, but I have only been able to find the querystring of the same context.
This is my hub, and within the send method i want to be able to match the id that is sent in to a particular connection id at the point of sending the message:
public class Chat : Hub
{
public string addMsg()
{
return "";
}
public void Send(string message, string id)
{
Clients.Client(Context.ConnectionId).receiveMessage(message);
}
}
Here is my client code, i want to pass the id of the person to send a message to to the server send method, and use the querystring value of the other connected user to match it to the id i am sending.
var chat = $.connection.chat;
chat.client.receiveMessage = function (message) {
alert("Received from server: " + message);
};
chat.addMsg = function (message) {
};
$("#sendMessage").click(function () {
chat.server.send($('#newMessage').val(), 6);
});
$.connection.hub.qs = "id=1";
$.connection.hub.start().done(function () {
var myClientId = $.connection.hub.id;
var qs = $.connection.hub.qs;
});
I hope my question makes sense, I have been trying to crack this for a while now, below are some links to some of the articles i have used to get to where i am now, I am just missing the last piece of the puzzle, please go easy on me :)
http://weblogs.asp.net/davidfowler/archive/2012/11/11/microsoft-asp-net-signalr.aspx
SignalR- send data to a specific client
https://github.com/SignalR/SignalR/wiki/QuickStart-Hubs

I don't think this is going to work the way you want it to. The connection ID is just that -- an identifier for a particular connection. SignalR itself doesn't know anything about authenticating users. It is, however, built on top of ASP.NET and all of your familiar authentication methods (Windows, Forms, etc.) work as you would expect.
Once ASP.NET has authenticated the user, you have access to this in your hubs as Context.User. It's now up to you to maintain a mapping between this user and one or more connection IDs. Besides browser refreshes, you might need to deal with a user accessing your service from multiple browsers or machines. Sending a message to this user means sending it to all of those browsers and machines.
Jabbr does all this and more. You really should take a look at that code for a good way to implement this.

How about using the Clients.Caller object int he hub, and overriding the OnConnected method:
public override Task OnConnected()
{
Clients.Caller.sendInitMessage(...);
return base.OnConnected();
}

Related

C# WebApi + React Native Chat

I am writing a ReactNative application with a C# Rest Api server. The application communicates via POST and GET requests (transfer of database records, user profiles, etc.). Now there is a need to create an internal chat in this application. I send messages from the client with POST requests, in which I pass the client token, the message text and the user name to which the message is sent (everything is encrypted). But there was a problem. As a chat user, receive new messages instantly. The first thing that came to mind was to also send a request to the server every 100 milliseconds to receive new messages. If there are messages, the server will return them to the client, if not, it will return an empty response. But I understand that this is some kind of crutch method and there may be a big load on the server. I started reading about SignalR and hubs. But I didn't find high-quality information. As far as I understand, messages will be delivered only if the second user is also connected to the hub. What if it's offline? Then the messages will not be delivered to him? I still don't understand in which direction I should work and which path to choose. Maybe this SignalR is not required at all. Which way should I choose? What kind of management architecture is needed to create such a chat between users inside the application? I hope for your understanding and desire to help the beginner).If possible, provide an example of the server (C#) and client (ReactNative js) code. Thank u.
[AcceptVerbs("POST")]
[Route("GetNewMessages")]
public List<BDMMessenge> GetNewMessages([FromBody] string token)
{
string user = db.bdmuser.Where(x => x.Token == token).Single().Email;
var messages = db.bdmmessenge.Where(x => x.ToUser == user && x.ClientGet == 0).ToList();
SetGetStatus(messages.Select(x => x.Id).ToList());
return messages;
}
[AcceptVerbs("POST")]
[Route("SendTextMessage")]
public DateTime SendTextMessage([FromBody] MMessageText _message)
{
string user = db.bdmuser.Where(x => x.Token == _message.Token).Single().Email;
var dataStatus = DateTimeOffset.Now.UtcDateTime;
db.bdmmessenge.Add(new BDMMessenge()
{
FromUser = user,
ToUser = _message.ToUser,
Type = "Text",
Content = _message.Content,
DataStatus = dataStatus,
ClientGet = 0
});
db.SaveChanges();
return dataStatus;
}

How to get response from IPN cryptocurrencies

We're trying to receive payment with cryptocurrencies using coinpayment IPN. We are able to create a request and able to do a payment. However, not able to get success or failure response while user come back to the seller side.
Here is how payment request created:
public ActionResult IPN()
{
var uri = new UriBuilder("https://www.coinpayments.net/index.php");
uri.SetQueryParam("cmd", "_pay_auto");
uri.SetQueryParam("merchant", "merchant_key");
uri.SetQueryParam("allow_extra", "0");
uri.SetQueryParam("currency", "USD");
uri.SetQueryParam("reset", "1");
uri.SetQueryParam("success_url", "http://localhost:49725/home/SuccessResponse"); //todo: redirect to confirm success page
uri.SetQueryParam("key", "wc_order_5b7b84b91a882");
uri.SetQueryParam("cancel_url", "http://localhost:49725/home/FailiureResponse");
uri.SetQueryParam("order_id", "36");
uri.SetQueryParam("invoice", "PREFIX-36");
uri.SetQueryParam("ipn_url", "http://localhost:49725/?wc-api=WC_Gateway_Coinpayments");
uri.SetQueryParam("first_name", "John");
uri.SetQueryParam("last_name", "Smith");
uri.SetQueryParam("email", "a#a.com");
uri.SetQueryParam("want_shipping", "1");
uri.SetQueryParam("address1", "228 Park Ave S&address2");
uri.SetQueryParam("city", "New York");
uri.SetQueryParam("state", "NY");
uri.SetQueryParam("zip", "10003-1502");
uri.SetQueryParam("country", "US");
uri.SetQueryParam("item_name", "Order 33");
uri.SetQueryParam("quantity", "1");
uri.SetQueryParam("amountf", "100.00000000");
uri.SetQueryParam("shippingf", "0.00000000");
return Redirect(uri.ToString());
}
This will be redirected to the coinpayment site, once payment done, it is showing the following screen.
And trying to get data when user click on back to seller's site, I have tried to get data using Request.Form, but not getting any value in form.
The same thing, working with this woocommerce code, but I have no idea of PHP and how they are dealing with it.
Any thought to get IPN response?
Note: there is no development documentation or sample code available for IPN in .NET
Edit
I'm trying to get value from IPN success
Public ActionResult SuccessResponse()
{
var ipn_version = Request.Form["ipn_version"];
var ipn_id = Request.Form["ipn_id"];
var ipn_mode = Request.Form["ipn_mode"];
var merchant = Request.Form["merchant"];
var txn_id = Request.Form["txn_id"];
var status = Request.Form["status"];
return Content(status);
}
You cannot use localhost for a IPN callback. You must use a public domain name.
As an example I would change the following parameters:
var uri = new UriBuilder("https://www.coinpayments.net/api.php");
uri.SetQueryParam("success_url", "http://kugugshivom-001-site1.atempurl.com/Home/SuccessResponse");
uri.SetQueryParam("cancel_url", "http://kugugshivom-001-site1.atempurl.com/Home/FailiureResponse");
uri.SetQueryParam("ipn_url", "http://kugugshivom-001-site1.atempurl.com/Home/CoinPaymentsIPN"); // Public ActionResult CoinPaymentsIPN()
Since you are creating your own gateway you also need to implement it properly as described in the documentation at CoinPayments API and Instant Payment Notifications (IPN).
I have tested your success_url endpoint, and got status code: 100 (when entering status:100). I see you use form-data, but I don't know if that's on purpose / required.
Postman POST http://kugugshivom-001-site1.atempurl.com/Home/SuccessResponse
In Body tab form-data is selected with Bulk Edit values:
ipn_version:1.0
ipn_type:api
ipn_mode:hmac
ipn_id:your_ipn_id
merchant:your_merchant_id
txn_id:your_transaction_id
status:100
As updated answer stated by #Gillsoft AB, you should need to use valid IPN URL from the code end. Also webhook would not work with localhost. thus, you should listen the request with live server.
Simplest way to check webhook response is to use online tool such as Webhook Tester, it will provide an URL which you have to set as your IPN URL, whenever server will sends the data, you can simply see it to the web. To check that, create one URL and set as your IPN URL as below:
uri.SetQueryParam("ipn_url", "https://webhook.site/#/457f5c55-c9ce-4db4-8f57-20194c17d0ae");
After that run the payment cycle from local machine, payment server will sends notification to that IPN URL.
Make sure you understood it right! success_url and cancel_url are for user redirection, you will not get any response code over there, inspection of seller's store URL give your exact same URL that you have been passing though, so it is recommended to use unique URLs for each order(i.e add order id at last to the URL) which will give you an idea which order payment has been done or canceled.
http://localhost:49725/home/SuccessResponse?orderid=123
In order to test your local code, add following changes and deployed it to server.
1) Add one new method which will listen IPN response
[ValidateInput(false)]
public ActionResult IPNHandler()
{
byte[] param = Request.BinaryRead(Request.ContentLength);
string strRequest = Encoding.ASCII.GetString(param);
//TODO: print string request
//nothing should be rendered to visitor
return Content("");
}
2) Pass IPN URL while creating a request:
public ActionResult IPN()
{
var uri = new UriBuilder("https://www.coinpayments.net/index.php");
...
..
uri.SetQueryParam("success_url", "http://localhost:49725/home/SuccessResponse");
uri.SetQueryParam("cancel_url", "http://localhost:49725/home/FailiureResponse");
uri.SetQueryParam("ipn_url", "http://localhost:49725/home/IPNHandler");
....
..
return Redirect(uri.ToString());
}
You will get all status code responses in IPNHandler method.
Hope this helps!

Check if route is valid in RequestStartup in NancyFX

I have a self-hosted REST API in my wpf application, built using NancyFX. The application is used for updating firmware and running diagnostics on different consumer products that are connected to the computer with a USB cable.
A product must be connected to the computer in order to use the API. So I thought it would be smart to do this check in the overriden RequestStartup() method in WindsorNancyBootstrapper which means that the check can be done in one location, instead of in every module. It worked as expected. No modules will handle the request if a product isn't connected.
But this led to an unwanted side effect in the following scenario:
A product is not connected to the computer
The path is invalid
This will always return a 404 with a message saying that the device is not connected, instead of a "bad url" message. I could move the check to each module, but i'd hate doing so. What I want:
If the url is invalid, no matter if there's a connected device, always return a 404 "Bad url" response without involving any modules
if the url is valid, but there is no connected device, return a 400 "no connected device" without involving any modules
And I would like to do this in one place. I have looked around for a solution but I haven't found anything. I'm thinking that maybe my approach is a dead end. After all, I'm using the BeforeRequest pipeline which could mean that there's no way of validating the URL yet?
My method (simplified) looks like this at the moment:
protected override void RequestStartup(IWindsorContainer container, IPipelines pipelines, NancyContext context)
{
pipelines.BeforeRequest.AddItemToEndOfPipeline(ctx =>
{
// TODO: Here I would like to check if the url is valid in order to be able to return a 404 "bad url" response
if (!_hasConnectedDevice)
{
// ResponseBase is my base class for all my JSON responses
var response = new ResponseBase(ctx.Request.Url, Messages.DeviceNotConnected);
return new JsonResponse(response, new DefaultJsonSerializer())
{
StatusCode = HttpStatusCode.NotFound
};
}
if (!_deviceIsReady)
{
var response = new ResponseBase(ctx.Request.Url, Messages.DeviceNotReady);
return new JsonResponse(response, new DefaultJsonSerializer())
{
StatusCode = HttpStatusCode.BadRequest
};
}
return null;
});
// Catch all unhandled exceptions here.
pipelines.OnError += (ctx, ex) =>
{
var response = new ResponseBase(ctx.Request.Url, ex.Message);
return new JsonResponse(response, new DefaultJsonSerializer())
{
StatusCode = HttpStatusCode.InternalServerError
};
};
}
The best way I can think of to do this would be to do something similar to what we do with security where you create an extension method on INancyModule that adds something to the pipline that checks if the device is plugged in and ready and returns the relevant status code if it's not, otherwise it just returns null, then in each module you want to only work with the USB devices you add:
this.RequiresUsbThings(); // Or whatever you want to call it :)

Securing a Web Method

Say I've got a method in c# MVC to send email with ajax, like:
public class mailController : Controller {
SmtpClient mailserver = new SmtpClient("smtp.foo.com");
public string send(string from, string to, string subject = "", string body = "", string cc = "", string bcc = "") {
MailMessage message = new MailMessage(from, to, subject, body);
if (cc.Length > 0) {
message.CC.Add(cc);
}
if (bcc.Length > 0) {
message.Bcc.Add(bcc);
}
mailserver.Send(message);
return "MessageSent";
}
}
Is there anything I can do to make this more secure? I mean, as it stands anyone can type the relevant info into their address bar. http://www.foo.com/mail/send?from=etc If I want to use this for form submission, I can't password protect it, or I'd have to use that in the javascript, which is easy to find. I considered setting a cookie and using that as authentication, but that only goes so far. Is there a standard procedure for protecting ajax methods?
You need to validate on the server that the parameters are what you want them to be.
You need to implement a secure session token, to prevent unauthorized users (those without valid sessions) from being able to send an email. This is basically no different than any other cross site request forgery (CSRF) attack vector. If you need any additional information just Google 'CSRF protection ASP.NET`' or similar to get some more concrete examples of how to do this.
Your requirements sound mutually exclusive.
If you do want to leave it public, but you don't want it abused, then maybe you could provide some sort of throttle where you only allow x number of requests from a specific IP address.
You can also use mailto: in an HTMLform to prompt the client to send the email.
As a start you can always store the IP that accessed your controller, if same IP is trying to send mail in specific frequency that you define you can deside to block it ot whatever...
at second you can generate a random number in your mailing page that will be send to the controller -> this will allow you to verify that the mail is sent from your site and not from third party

SignalR Client connection issues? Can't connect to path with HubConnection()

I've been trying to look in the wiki about doing this, I'm following it, but I seem to be missing something?
So here is where I am at:
I have a client side JS that works fine locally.
I now want to send something via an API to update the client side version.I should use SignalR Client right?
This is what i have:
var connection = new HubConnection("http://localhost/test/echo", useDefaultUrl: false);
Global.asax
RouteTable.Routes.MapConnection<MyConnection>("echo", "echo/{*operation}");
I'm getting an error along the lines of no cancellation token is declared....
Is it that I'm not hitting my HubConnection page?
If you need me to clarify let me know.
Thanks,
UPDATE:
Thanks for replying! I'm still uncertain on how a Hub can talk to a persistent connection?
This is what I have so far...
namespace ConnectionHubDemo{
public class ChatHub : Hub
{
public void SendMessage(string message)
{
Clients.NewMessage(message);
}
}
public class ConnectionHub
{
public string test(string data)
{
//Will this talk to my PersistentConnection?
var connection = new HubConnection("http://localhost/test", false);
var myHub = connection.CreateProxy("ConnectionHubDemo.ServiceHub");
//How would I send a message to my persisten connection?
//myHub...
//If succcessful bla bla bla
return data;
}
}
}
That's because you're not using Hubs. You're mixing Hubs and PersistentConnections. On the server Hubs are automatically routed so there's no need to map anything (see https://github.com/SignalR/SignalR/wiki/Hubs). From the wiki:
Unlike low level PersistentConnections, there's no need to specify a route for the hub as they are automatically accessible over a special url (/signalr). This url is configurable:
To make the client side work you just declare a HubConnection with the root url (see https://github.com/SignalR/SignalR/wiki/SignalR-Client-Hubs). Again from the documentation:
To connect to a hub using SignalR, create a HubConnection with the appropriate url.
NOTE: This url will not point to a specific connection. But will instead point to the root of your site.
Example
var connection = new HubConnection("http://mysite/");
So in your case, this would be:
var connection = new HubConnection("http://localhost/test");
Hope this helps.
UPDATE
Hubs DO NOT talk to persistent connections. All you have to do is follow the documentation. My answer above shows how to use Hubs on the server and on the client.
If you want to use Persistent connections then look at the documentation https://github.com/SignalR/SignalR/wiki/PersistentConnection (Server) and https://github.com/SignalR/SignalR/wiki/SignalR-Client (Client).

Categories

Resources