Check if route is valid in RequestStartup in NancyFX - c#

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 :)

Related

Validating PayPal Webhook calls with PayPal .NET SDK in Sandbox

I've been trying to set up PayPal Webhooks (in Sandbox mode) to receive notifications about declined and successful payments. My problem is that I can't get validation working. Some details about my attempts:
The app is an OWIN self-hosted Web API 2.
Hosted as an Azure Web App, tested on Azure as well.
I set the Paypal Webhook receiver URL in the Paypal dashboard to the URL of my endpoint on Azure.
I used the Paypal Webhooks simulator from the Paypal dashboard to send a message to the Azure endpoint.
I tried listening for Webhook calls two ways:
ASP.NET Webhook Receivers (http://blogs.msdn.com/b/webdev/archive/2015/09/04/introducing-microsoft-asp-net-webhooks-preview.aspx), which didn't work. I get the error message "WebHook validation failed: "
Tried creating a Web API endpoint to receive and validate the request, didn't work either. Code here:
[HttpPost]
public async Task<IHttpActionResult> PaymentCaptureCompleted()
{
// Get the received request's headers
NameValueCollection nvc = new NameValueCollection();
foreach (var item in Request.Headers)
{
nvc.Add(item.Key, string.Join(",", item.Value));
}
// Get the received request's body
var requestBody = await Request.Content.ReadAsStringAsync();
var isValid = WebhookEvent.ValidateReceivedEvent(Api, nvc, requestBody, ConfigurationManager.AppSettings["paypal.webhook.id"]);
if (isValid)
{
return Ok();
}
else
{
return BadRequest("Could not validate request");
}
}
There are a lot more details to this of course, but I'm not sure how much information is required to answer my question. Just let me know what you need and I'll edit this question.
Please refer PayPal Dot Net SDK for code samples. https://github.com/paypal/PayPal-NET-SDK
Also if your simulator is not working, to rule out if there is something wrong with the configuration of webhook or the azure, you may want to use Runscope. Ypu can configure a Runscope bucket as a webhook endpoint and If you are getting a webhook notification there, you may need to make changes in the Azure config.
Really don`t go to the documentation. It is old but objects is still good.
You can use WebhookEvent class for it.
Just use this action in your controller.
public JsonResult Index(WebhookEvent event)
{
// event has all the data
return Json(new { success = true });
}
Validation does not work for either IPN sandbox nor Webhook events from the mock. It's stated in the PayPal documentation. Validation only works on the production environment of PayPal.
Wrap WebhookEvent.ValidateReceivedEvent in a try catch. If the call fails, it can just hang without that. The exception will show you the error.
try
{
var isValid = WebhookEvent.ValidateReceivedEvent(apiContext, nv, requestBody, hookId);
}
catch(Exception e)
{
}
In my case the exception said "Unable to load trusted certificate"

Exception from MVC API to MVC site gives error

I have created an MVC (4) Web API which works fine. It has a simple login-method that throws an exception when the user cannot be found.
Besides the API I created a simple website that calls the API by HttpClient:
public T ExecutePost<T>(string apiUrl, IEnumerable<KeyValuePair<string, string>> postData) {
HttpContent content = null;
if (postData != null)
content = new FormUrlEncodedContent(postData);
var a = _client.PostAsync(apiUrl, content).ContinueWith(httpResponseMessage =>
JsonConvert.DeserializeObject<T>(httpResponseMessage.Result.Content.ReadAsStringAsync().Result)
);
return a.Result;
}
You can call this method as
ExecutePost<User>("url_to_controller_action_api", list_with_keys_and_values_to_post)
When this method calls the API with the postData-fiels username and password (both are correct and known by the system) an object called User will be returned... Works like a charm.
When I call this method with the wrong username and/or password, the API throws an exception (User not found), but the method ExecutePost throws an exception aswell and the web page shows a nice, yellow-isch, red-letter page with errors that the normal user does not understand. The reason is easy: The data sent back from the API is not the same as the data that can be put in the object User.
So, what I would like to do is deserialize the exception, from the API, in an object called Error and return that to the controller of the MVC website, so I can put the error "User not found" on the page with the correct design of the site.
What is the best way to do this? Try-catch in all actions? Doesn't feel right to me... So suggestions are more than welcome.
Most things I found were API-side stuff, but I want to fetch and handle the exception on the site-side.
Thanks in advance
On your Web API when you detect an invalid login, make sure that an HttpResponseException gets thrown with a status code of 401 (HttpStatusCode.Unauthorized).
//login failed:
var resp = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent("Invalid Username or password")
};
throw new HttpResponseException(resp);
In your calling code, you can then first check if httpResponseMessage.StatusCode==HttpStatusCode.OK before you attempt to deserialise the response into a User.
var a = _client.PostAsync(apiUrl, content).ContinueWith(httpResponseMessage => {
if (httpResponseMessage.Status!=HttpStatus.OK)
{
string ErrorMessage = httpResponseMessage.Result.Content.ReadAsStringAsync();
//and whatever you want to do with that error message here
}
else
{
try
{
var user = JsonConvert.DeserializeObject<T>(httpResponseMessage.Result.Content.ReadAsStringAsync().Result);
}
catch(Exception ex)
{
//honest to goodness unrecoverable failure on the webapi.
//all you can do here is fail gracefully to the caller.
}
}//endif (Status OK)
}//end anonymous function
);
If it's not a 200 then you can execute a second check to see if it's a 401 (and have some specific handling for invalid login) or a more general 500 (something went wrong on the server), etc, and get the actual error message of the exception ("Invalid Username or password") to send back to the client:
var errorMessage = httpResponseMessage.Content.ReadAsStringAsync().Result;
Finally, even if it is 200 then you should still try...catch the deserialisation operation so you can gracefully handle any issues with the returned data, if for whatever reason the data can't be turned into a User object.

SignalR 1.0 - send data to a specific client

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();
}

How to check if a web service is up and running without using ping?

How can i check if a method in a web service is working fine or not ? I cannot use ping. I still want to check any kind of method being invoked from the web service by the client. I know it is difficult to generalize but there should be some way.
I use this method and it works fine :
public bool IsAddressAvailable(string address)
{
try
{
System.Net.WebClient client = new WebClient();
client.DownloadData(address);
return true;
}
catch
{
return false;
}
}
The only way to know if a web service method is working "fine" is to call the method and then to evaluate whether the result is "fine". If you want to keep a record of "fine" vs. time, then you can log the result of the evaluation.
There's no more general way to do this that makes any sense. Consider:
You could have code that creates an HTTP connection to the service endpoint, but success doesn't tell you whether the service will immediately throw an exception as soon as you send it any message.
You could connect and send it an invalid message, but that doesn't tell you much.
You could connect and send it a valid message, then check the result to ensure that it is valid. That will give you a pretty good idea that when a real client calls the service immediately afterwards, the real client should expect a valid result.
Unless the service takes that as an opportunity to crash, just to spite you!
The best technique would be to use WCF tracing (possibly with message-level tracing) to log what actually happens with the service, good or bad. A human can then look at the logs to see if they are "fine".
Powershell is by far an easy way to 'ping' a webservice endpoint.
Use the following expression:
Test-NetConnection -Port 4408 -ComputerName 192.168.134.1
Here is a failure response for a port that does not exist or is not listening;
WARNING: TCP connect to 192.168.134.1:4408 failed
ComputerName : 192.168.134.1
RemoteAddress : 192.168.134.1
RemotePort : 4408
InterfaceAlias : Ethernet0
SourceAddress : 192.168.134.1
PingSucceeded : True
PingReplyDetails (RTT) : 0 ms
TcpTestSucceeded : False
Here is a success result if the address/port is listening and accessible:
ComputerName : 192.168.134.1
RemoteAddress : 192.168.134.1
RemotePort : 4407
InterfaceAlias : Ethernet0
SourceAddress : 192.168.134.1
TcpTestSucceeded : True
just use try catch inside the method of your webservice and log exceptions to a log file or to the event log.
Example:
[OperationContract]
public bool isGUID(string input)
{
bool functionReturnValue = false;
try
{
Guid guid;
functionReturnValue = Guid.TryParse(input, guid);
}
catch (Exception ex)
{
Log.WriteServerErrorLog(ex);
}
return functionReturnValue;
}
You don't need to ping the webservice, but instead ping the server with a watchdog service or something. There is no need to "ping" the webservice. I also think you don't need to do this anyway.
Either your webservice works or it doesn't because of bad code.
You may try curl. It's a Linux tool, should be there in Cygwin too.
$ curl http://google.com
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
here.
</BODY></HTML>
There are lots of options; examples can be found in the 'net.
You can write your self a little tool or windows service or whatever you need then look at these 2 articles:
C#: How to programmatically check a web service is up and running?
check to if web-service is up and running - efficiently
EDIT:
This was my implementation in a similar scenario where I need to know if an external service still exists every time before the call is made:
bool IsExternalServiceRunning
{
get
{
bool isRunning = false;
try
{
var endpoint = new ServiceClient();
var serviceUri = endpoint.Endpoint.Address.Uri;
var request = (HttpWebRequest)WebRequest.Create(serviceUri);
request.Timeout = 1000000;
var response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
isRunning = true;
}
#region
catch (Exception ex)
{
// Handle error
}
#endregion
return isRunning;
}
}
As I see it, you have 2 options:
If you can access the server it is running on, Log every call (and exceptions thrown). Read the log file with a soft like baretail that updates as the file is being written.
If you can't access the server, then you have to make the webservice write that log remotely to another computer you have access to.
Popular loggers have this functionality built in. (Log4Net, ...)
You could also use tracing.
http://msdn.microsoft.com/en-us/library/ms732023.aspx
http://msdn.microsoft.com/en-us/library/ms733025.aspx

Real-Time Subscriptions

Good afternoon,
I'm using version 5.4.1 of the Facebook C# SDK. I should note that I am using the source code directly rather than the DLLs (in case this makes any difference).
So the fact that filter attributes are setup is awesome (thank you dev team :).
My issue is occurring during the initial request (before I get to using verifying the GET response from Facebook)
Here is my initial request:
dynamic result = fb.Post(
string.Format("/{0}/subscriptions",
FacebookApplication.Current.AppId),
new Dictionary<string, object>
{
{"object", "user"},
{"fields", "friends"},
{
"callback_url",
"http://localhost:16917/subscription/verify"
},
{
"verify_token",
"77FB802F-1147-48F0-BB0F-E4E9BC1FBCFC"
}
});
I'm finding that an exception is internally being thrown and via Fiddler I'm seeing that the request is never going out. The exception is:
$exception {"(OAuthException) (#15) This method must be called with an app access_token."} System.Exception {Facebook.FacebookOAuthException}
I initially thought this may be related to Facebook.FacebookClient's PrepareRequest method:
if (httpMethod == HttpMethod.Get)
{
// for GET, all parameters goes as querystrings
input = null;
queryString.Append(FacebookUtils.ToJsonQueryString(parameters));
}
else
{
if (parameters.ContainsKey("access_token"))
{
queryString.AppendFormat("access_token={0}", parameters["access_token"]);
parameters.Remove("access_token");
}
}
but commenting out the line parameters.Remove("access_token"); made no difference.
Any help would be greatly appreciated!
What access_token are you using?
Are you using a User's access token, or an App access token?
If you are using an User's access token take a look here http://developers.facebook.com/docs/authentication/#app-login on how to get an App access token.
You will need to use the app access_token.
You can easily create an app access_token using the following constructor.
var fb = new FacebookClient("appid", "appsecret");
dynamic result = fb.Post( .... );

Categories

Resources