Url rewrite in exception middleware - asp.net-mvc

I'm trying to do some custom exception handling and in there I need to redirect.
They way to go should be like this
app.UseExceptionHandler(appBuilder =>
{
appBuilder.Use(async (ctx, next) =>
{
ctx.Request.Path = "/Error";
await next();
});
});
But nothing happens, just a blank 500 page.
Any ideas except the use of
ctx.Response.Redirect("/Error")

When you use the overload of UseExceptionHandler accepting an Action<IApplicationBuilder>, you need to configure a full pipeline for the sub-builder inside to re-execute the pipeline on the exception branch. In your code, you just set the Request.Path but it is then not handled by any code. You need to add an MVC middleware as the terminal at the end. You can configure it just like you configure your main pipeline (UseMvc, UseEndpoints). In this case the terminal just need to work with the specific request path you set before. Here's the code:
app.UseExceptionHandler(appBuilder => {
appBuilder.Use(async (ctx, next) => {
ctx.Request.Path = "/Error";
await next();
});
//add the terminal to handle the branched request
appBuilder.UseMvc();
});
Now when you run into some unhandled exception, it should work just like app.UseExceptionHandler("/Error").

According to your description, I suggest you could firstly try to understand how the exceptionhanlder works.
According to the source codes, you could find if you want to write the custom middleware ,you should use the second function like this:
public static IApplicationBuilder UseExceptionHandler(this IApplicationBuilder app, Action<IApplicationBuilder> configure)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
if (configure == null)
{
throw new ArgumentNullException(nameof(configure));
}
var subAppBuilder = app.New();
configure(subAppBuilder);
var exceptionHandlerPipeline = subAppBuilder.Build();
return app.UseExceptionHandler(new ExceptionHandlerOptions
{
ExceptionHandler = exceptionHandlerPipeline
});
}
If you use this function, you could find it will still call the ExceptionHandlerMiddleware with its new exceptionHandlerPipeline. And in the ExceptionHandlerMiddleware , you could find it will call this request delaget.
So if you don't catch the exception and directly set the context path it will not work. So I suggest you could try to use below codes:
app.UseExceptionHandler(appBuilder =>
{
app.Use(async (context, next) =>
{
try
{
await next();
}
catch (Exception ex)
{
ClearHttpContext(context);
var exceptionHandlerFeature = new ExceptionHandlerFeature()
{
Error = ex,
Path = "/Home/Index",
};
context.Request.Path = "/Home/Error";
context.Features.Set<IExceptionHandlerFeature>(exceptionHandlerFeature);
context.Features.Set<IExceptionHandlerPathFeature>(exceptionHandlerFeature);
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.OnStarting(ClearCacheHeaders, context.Response);
await next();
}
});
});
ClearCacheHeaders method:
private static Task ClearCacheHeaders(object state)
{
var headers = ((HttpResponse)state).Headers;
headers[HeaderNames.CacheControl] = "no-cache,no-store";
headers[HeaderNames.Pragma] = "no-cache";
headers[HeaderNames.Expires] = "-1";
headers.Remove(HeaderNames.ETag);
return Task.CompletedTask;
}

Related

Where should I put completer.complete() in this series of Future functions?

My function have to create a directory, and copy the entire folder hierarchy from another directory to this new one. All of the operation are done asynchronously, but I want this function to return a Future that when I call the .then(result) on it, will have done all of the asynchronously work.
But I don't know where exactly I should put my completer.complete() to achieve that.
Future<Directory> createCopyDirectory(Directory directoryToCreate){
Completer<Directory> completer = new Completer<Directory>();
completer.complete(
directoryToCreate.create().then((directory){
Directory contentToCopy = new Directory(globalPathOfDirectoryToCopy);
List<Future> creatingContent = new List<Future>();
contentToCopy.list(recursive:true, followLinks:false).forEach((f){
if (f is File){
File fileToCreate = new File(f.path.replaceFirst('pages', userID));
creatingContent.add(fileToCreate.create(recursive:true).then((_){
f.readAsString().then((fileContent){
fileToCreate.writeAsString(fileContent);
});
}));
}
});
return Future.wait(creatingContent).then((_){ return directoryToCreate;});
})
);
return completer.future;
}
I precise that my function work like expected, But if I try to access directly the content I should have created in this function, like in the then() call, Dart bring me an expection like I have not created the content. So the completer.complete() is surely badly placed and call then() before the content has been created.
I have tried with the completer.complete() on the ending Future.wait(creatingContent) or by replacing return directoryToCreate by completer.complete(directoryToCreate) but the result is the same.
I am a bit confused on the way to build a proper Future based function in this kind of situation.
You shouldn't need a Completer here.
Future<Directory> createCopyDirectory(Directory directoryToCreate) {
return directoryToCreate.create().then((directory) {
String userID = split(userDirectory.path).last;
Directory contentToCopy = new Directory(globalPathOfDirectoryToCopy);
List<Future> creatingContent = new List<Future>();
return contentToCopy
.list(recursive: true, followLinks: false)
.forEach((File f) {
if (f is File) {
File fileToCreate = new File(f.path.replaceFirst('pages', userID));
creatingContent.add(fileToCreate.create(recursive: true).then((_) {
return f.readAsString().then((fileContent) {
return fileToCreate.writeAsString(fileContent);
});
}));
}
}).then((_) {
return Future.wait(creatingContent).then((_) {
return directoryToCreate;
});
});
});
}
Just to demonstrate how you could use the Completer:
Future<Directory> createCopyDirectory(Directory directoryToCreate) {
Completer<Directory> completer = new Completer<Directory>();
directoryToCreate.create().then((directory) {
String userID = split(userDirectory.path).last;
Directory contentToCopy = new Directory(globalPathOfDirectoryToCopy);
List<Future> creatingContent = new List<Future>();
contentToCopy.list(recursive: true, followLinks: false).forEach((f) {
if (f is File) {
File fileToCreate = new File(f.path.replaceFirst('pages', userID));
creatingContent.add(fileToCreate.create(recursive: true).then((_) {
return f.readAsString().then((fileContent) {
return fileToCreate.writeAsString(fileContent);
});
}));
}
}).then((_) => Future
.wait(creatingContent)
.then((_) => completer.complete(directoryToCreate)));
});
return completer.future;
}

In NServiceBus full duplex application Server could not send/reply/return message

I have created a ASP.Net Web API project and using this link. NServiceBus is integrated with web api. Here is my configuration at web api as a client.
Configure.Serialization.Xml();
Configure.Transactions.Enable();
Configure.With()
.DefineEndpointName(Constants.ClientName)
.DefaultBuilder()
.ForWebApi()
.Log4Net()
.UseTransport<Msmq>()
.PurgeOnStartup(false)
.UnicastBus()
.ImpersonateSender(false)
.CreateBus()
.Start();
This is how I'm sending message to Server
var response = await Bus.Send(Constants.ServerName, request)
.Register<ResponseModel>((NServiceBus.CompletionResult completionResult) =>
{
ResponseModel responseMessage = null;
if (completionResult != null && completionResult.Messages.Length > 0)
{
var status = completionResult.Messages[0] as RequestStatus?;
if (status == RequestStatus.Successful)
{
responseMessage = TransactionManager.TransactionDictionary[request.RequestId].ResponseModel;
}
}
return responseMessage;
});
This is how I'm sending response from Server. I have commented some lines to show what I have already tried.
public void Handle(RequestModel message)
{
ProcessRequest(message).RunSynchronously();
}
private async Task ProcessRequest(RequestModel message)
{
....
ResponseModel response = new ResponseModel();
response.RequestId = message.RequestId;
response.Result = await responseMessage.Content.ReadAsStringAsync();
//Bus.Send(Util.Constants.ClientName, response);
//Bus.Reply(response);
//Bus.Reply<ResponseModel>((ResponseModel response) =>
//{
// response = Bus.CreateInstance<ResponseModel>(r =>
// {
// r.RequestId = message.RequestId;
// r.Result = responseMessage.Content.ReadAsStringAsync().Result;
// });
//});
await Bus.Send(Util.Constants.ClientName, response).Register((NServiceBus.CompletionResult completionResult) =>
{
if (completionResult != null && completionResult.Messages.Length > 0)
{
var msg = completionResult.Messages[0];
if (msg != null)
{
var status = (RequestStatus)msg;
return status;
}
}
return RequestStatus.Error;
});
....
}
From any of the above response methods ultimately all messages end up in error queue.
Previously I was getting 'Could not enlist message' error. Now it is not throwing that error. But Server could not send message to Client.
I could not get what I'm doing wrong. Please also suggest if you see any scope for improvements.
I'm not sure if TransactionScope work correctly with async/await in C#. According to this question (Get TransactionScope to work with async / await) in .NET 4.5.1 there was introduced option for TransactionScope that enable mixing it with async/await. Unfortunately NServiceBus doesn't support .NET 4.5/4.5.1 so try just remove async/await.

How can I access the result of the response of HttpRequest in Dart?

After many attempts to get the content of the response in HttpRequest, I failed completely to know or understand why I can't have what I want, and I must mention that I can log and manipulate the response only inside an onReadyStateChange (onLoad and onLoadEnd are giving me the same results!), but I really want that value outside the callback.
Here is the part of code that I'm stuck with
Map responsData;
req=new HttpRequest()
..open(method,url)
..send(infojson);
req.onReadyStateChange.listen((ProgressEvent e){
if (req.readyState == HttpRequest.DONE ){
if(req.status == 200){
responsData = {'data': req.responseText};
print("data receaved: ${ req.responseText}");
//will log {"data":mydata}
}
if(req.status == 0){
responsData = {'data':'No server'};
print(responsData );
//will log {"data":No server}
}
}
});
//anything here to get responsData won't work
You have to assign an onLoad callback before you call send.
I'm not sure what you mean with only inside an onReadyStateChange.
Maybe you want to assign the responseText to a variable outside the the callback.
Create a method:
Future<String> send(String method, String url, String infojson) {
var completer = new Completer<String>();
// var result;
req=new HttpRequest()
..open(method,url)
..onLoad.listen((event) {
//print('Request complete ${event.target.reponseText}'))
// result = event.target.responseText;
completer.complete(event.target.responseText);
})
..send(infojson);
return completer.future;
}
and call this method like
var result;
send(method, url).then(
(e) {
// result = e;
print('Request complete ${e}'));
});

How do I register multiple handlers for a HttpServer, in Dart?

(I'm using the new lib v2 version of dart:io.)
I'd like to register multiple handlers for an HttpServer, specifically a WebSocketTransformer and other arbitrary handlers. Something like this:
// pseudo-code
var server = HttpServer;
server.register('/foo', someHandlerFunction); // 1
server.register('/bar', someOtherHandlerFunction); // 2
server.register('/ws', webSocketHandler); // 3
If #1 matches, then #2 isn't tested, and so on. So, it's greedy.
I've seen samples with just one handler. How do I register many handlers? Thanks in advance!
New answer: Use the route package: http://pub.dartlang.org/packages/route
Here's your example using route's serve() method:
HttpServer.bind('127.0.0.1', 8889).then((server) {
var router = new Router(server)
..serve('/ws').transform(new WebSocketTransformer()).listen(handleWebSocket)
..serve('/foo').listen((req) {
req.response..addString('foo')..close();
});
});
Router automatically catches unhandled requests and sends a 404, though soon you'll be able to override that with a defaultStream you can listen to.
Router also supports filters, useful for logging, auth, compression, etc.:
HttpServer.bind('127.0.0.1', 8889).then((server) {
var router = new Router(server)
..filter(new RegExp(r'/.*'), (req) {
//log all requests
_logger.info("request: $req");
return new Future.immediate(true); // keep processing request
})
..filter(new Regexp(r'/secure/.*'), (req) {
// check authentication asynchronously
return getUserFromRequest(req).then((user) {
if (user == null) {
sendRedirect('/login'); // sendRedirect coming soon
return false; // stop processing request
} else {
return true; // keep processing
}
});
})
..serve(/* ... */ );
});
Here's how the API docs recommend to register a WebSocket handler:
server
.where((request) => request.uri.path == "/ws")
.transform(new WebSocketTransformer()).listen((webSocket) => ...);
However, the server is a single-subscription stream. Once a listen is attached, you can't attach other listeners.
What I really want is for something to look at an event, decide if it can handle it, and if so then route it to another stream. Otherwise, pass it along. This way, the event (in this case an HttpRequest object) is passed along a chain until it's handled.
I built a TakeAndRoute class that extends StreamEventTransformer. The TakeAndRoute uses a function to determine if it should grab the event and route it to another stream, or simply forward it along.
Here's what I came up with:
import 'dart:io';
import 'dart:async';
handleWebSocket(WebSocket webSocket) {
webSocket.listen((event) {
if (event is MessageEvent) {
/* Handle message. */
} else if (event is CloseEvent) {
/* Handle closed. */
}
});
}
typedef bool ShouldTake(e);
typedef void RouteTo(Stream stream);
typedef void HandleEvent(e);
class TakeAndRoute<S, T> extends StreamEventTransformer<S, T> {
ShouldTake shouldTake;
RouteTo routeTo;
StreamController controller = new StreamController();
HandleEvent handler;
TakeAndRoute(this.shouldTake, {this.routeTo, this.handler}) {
if (routeTo != null) routeTo(controller.stream);
}
handleData(event, StreamSink sink) {
print("handling");
if (shouldTake(event)) {
if (routeTo != null) {
controller.add(event);
}
if (handler != null) {
handler(event);
}
} else {
sink.add(event);
}
}
}
main() {
HttpServer.bind('127.0.0.1', 8888)
.then((HttpServer server) {
server
.transform(new TakeAndRoute<HttpRequest, HttpRequest>(
(req) => req.uri.path == '/ws',
routeTo: (stream) => stream.transform(new WebSocketTransformer()).listen(handleWebSocket)))
.transform(new TakeAndRoute<HttpRequest, HttpRequest>(
(req) => req.uri.path == '/foo',
handler: (req) {
print('got foo');
req.response.addString("foo");
req.response.close();
}))
.listen((req) {
print("got 404 for ${req.uri}");
req.response.statusCode = 404;
req.response.close();
});
});
}
Admittedly, this might be overkill.
Here is a more manual, but shorter way to do it:
HttpServer.bind('127.0.0.1', 8889)
.then((HttpServer server) {
var sc = new StreamController();
sc.stream.transform(new WebSocketTransformer()).listen(handleWebSocket);
server.listen((HttpRequest request) {
print("new connection from ${request.uri.scheme} ${request.uri}");
// See https://code.google.com/p/dart/issues/detail?id=8825
//if (request.uri.scheme == 'ws') {
if (request.uri.path == '/ws') {
sc.add(request);
} else if (request.uri.path == '/foo') {
request.response.addString('foo');
request.response.close();
} else {
print("got 404 for ${request.uri}");
request.response.statusCode = 404;
request.response.close();
}
});
});
Notice how I had to create a StreamController so I could pump events to WebSocketTransformer

problems in silverlight 4 when using Action callbacks to check for successful file upload

So the async requirement for silverlight ends up in some really convoluted code!!
Im uploading a file just exactly like this answer suggests.
The difference is Im posting the file to an MVC action method. Everything works file except, like I commented on the bottom of that answer, I don't get any callback for when the file DOES NOT successfully upload.
So I created another action method in my mvc app (Services/CheckForFile/{id}) and it returns a string depending on whether the file is found.
Now, how and when do I call this mvc action method is the problem:
void DoUpload() { //Gets call on BtnUpload.Click
//opn is an OpenFileDialog
up.UploadFile(_filename, opn.File.OpenRead(),
e =>
{
//do some ui stuff here.
BeginCheck();// calling this causes PROBLEMS!
});
}
private void BeginCheck()
{
Uploader up = new Uploader();
up.CheckForFile(_filename, success =>
{
if (!success)
{
MessageBox.Show("There was problem uploading the file. Please try again", "Error", MessageBoxButton.OK);
}
});
}
Here is the problem:
When the BeginCheck() function runs, the file, for some reason, NEVER uploads! If I comment it out it does!? It seems like The BeginCheck() runs during the upload or something? Shouldn't it run after!?
How/where would I call BeginCheck() after the upload, to ensure the file has been uploaded?
Here is how I defined the Uploader class:
public class Uploader
{
public void UploadFile(string fileName, Stream data, Action<Exception> callback)
{
UriBuilder ub = new UriBuilder(_mvcurl+"Services/UploadFile/" + fileName);
WebClient c = new WebClient();
c.OpenWriteCompleted += (sender, e) =>
{
try
{
PushData(data, e.Result);
e.Result.Close();
data.Close(); //this does not block.
callback(null);//this ALWAYS hits!
}
catch (Exception err)
{
if (callback != null)
{
callback(err);
}
}
};
c.OpenWriteAsync(ub.Uri);
}
public void CheckForFile(string filename, Action<bool> callback)
{
UriBuilder ub = new UriBuilder(_mvcurl+"Services/CheckForFile/" + fileName);
WebClient c = new WebClient();
c.OpenReadCompleted += (sender, e) =>
{
using (StreamReader sw = new StreamReader(e.Result))
{
if (sw.ReadToEnd().Equals("Found", StringComparison.InvariantCultureIgnoreCase))
{
callback(true);
}
else
{
callback(false);
}
}
};
c.OpenReadAsync(ub.Uri);
}
private void PushData(Stream input, Stream output)
{//4KB is not a limitation. We only copy 4Kb at a time from in to out stream
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) != 0)
{
output.Write(buffer, 0, bytesRead);
}
}
}
I'm embarrased to say that the original answer of mine to which you refer isn't entirely accurate. It seems to work for what the OP wanted but in fact the code doesn't block at the point that I thought it did. In reality what you are actually looking for is the WriteStreamClosed event, its here that you can discover any failure of the request.
Here is an ammended version that works the way you are expecting:-
public void UploadFile(string fileName, Stream data, Action<Exception> callback)
{
UriBuilder ub = new UriBuilder(_mvcurl+"Services/UploadFile/" + fileName);
WebClient c = new WebClient();
c.OpenWriteCompleted += (sender, e) =>
{
try
{
PushData(data, e.Result);
e.Result.Close();
data.Close(); //this does not block.
}
catch (Exception err)
{
if (callback != null)
callback(err);
}
};
c.WriteStreamClosed += (sender, e) =>
{
if (callback != null)
callback(e.Error);
}
c.OpenWriteAsync(ub.Uri);
}
Now your BeginCheck will only run after the server has responded to the file upload.

Resources