Error handling in Bot Framework dialogs - c#

How can I catch all exceptions in dialogs? Is there something like ASP.NET Exception Filter?
I want to send different messages to user depending on exception type.
Thank you

You are right about the fact that you can use ExceptionFilter.
You just have to do the following:
Create your ExceptionFilter class, for example to force the tracking of the exception in Application Insights (or in your case handle specific exception types):
using Microsoft.ApplicationInsights;
using System.Net.Http;
using System.Web.Http.Filters;
namespace BotDemo.App_Start
{
public class ExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext ctx)
{
HandleError(ctx);
}
private static void HandleError(HttpActionExecutedContext ctx)
{
ctx.Response = new HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError)
{
Content = new StringContent(ctx.Exception.Message)
};
var client = new TelemetryClient();
client.TrackException(ctx.Exception);
}
}
}
Don't forget to define your exception filter in your Application_Start():
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configuration.Filters.Add(new ExceptionFilter());
...
That's it.
In fact Bot Framework template is using ASP.Net, so you have all the normal features.

Related

Object Reference not set to an instance in ASP.Net Core 3.0

In Manage.Data project I've Admin repository and I've implemented service calls in admin repository. I've a another project Manage.API and I've a class called Authenticate.cs. I want to call GetLoginInfo() method from Authenticate.cs class file.
private IManageRepository _memRepository;
_memRepository.GetLoginInfoAsync("","",Guid.Empty);
Its not working. Could anyone please guide me.
CustomAuthenticate.cs
namespace CamManager_API
{
[AttributeUsage(AttributeTargets.Class)]
public class CustomAuthorization : Attribute, IAuthorizationFilter
{
private IManageRepository IManageRepository;
public CustomAuthorization(IManageRepository manageRepository)
{
this._manageRepository = manageRepository;
}
/// <summary>
/// This will Authorize User
/// </summary>
/// <returns></returns>
public void OnAuthorization(AuthorizationFilterContext filterContext)
{
if (filterContext != null)
{
Microsoft.Extensions.Primitives.StringValues authTokens;
filterContext.HttpContext.Request.Headers.TryGetValue("Authorization", out authTokens);
var _token = authTokens.FirstOrDefault();
if (_token != null)
{
string authToken = _token;
if (authToken != null)
{
var responseModel = _manageRepository.GetLoginInfoAsync("","",Guid.Empty);
}
}
else
{
}
}
}
public bool IsValidToken(string authToken)
{
//validate Token here
return true;
}
}
}
ManageRepository.cs
using Dapper;
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Threading.Tasks;
namespace CamManager.DataAccess
{
public class ManageRepository : SqlRepository<Member>, IManageRepository
{
public ManageRepository(string connectionString) : base(connectionString) { }
public override async Task<Login> GetLoginInfoAsync(string firstName, string password, Guid accessKey)
{
using (var conn = GetOpenConnection())
{
var parameters = new DynamicParameters();
parameters.Add("#Firstname", firstName, System.Data.DbType.String);
parameters.Add("#Password", password, System.Data.DbType.String);
parameters.Add("#AccessKey", accessKey, System.Data.DbType.Guid);
return await conn.QueryFirstOrDefaultAsync<Login>("Login", parameters, commandType: CommandType.StoredProcedure);
}
}
public override async Task<IEnumerable<Member>> GetAllAsync()
{
}
public override async Task<Member> FindAsync(long id)
{
}
public override async Task<Result> InsertAsync(Member entity)
{
}
public override async Task<Result> UpdateAsync(Member entity)
{
}
public override async Task<Result> DeleteAsync(long id)
{
}
}
}
maybe you need to init your repository in the constructor... otherwise show us all file content to detect the exact problem
public class MainClass
{
private IManageRepository _memRepository;
public MainClass(IManageRepository _memRepository)
{
this._memRepository = _memRepository;
}
}
Add this code to your startup
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IManageRepository , ManageRepository >();
}
I think you forgot to register your Interface for the ASP dependency injection. Otherwise the DI cannot do anything. More information here
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IManageRepository, ManageRepositoryImplementation>();
}
Whereby ManageRepositoryImplementation is just a placeholder for
the class which implements the interface IManageRepository and you want to create an instance of. This
information only you can know.
Then do it like Lajil Adel said:
public class MainClass
{
private IManageRepository _memRepository;
public MainClass(IManageRepository _memRepository)
{
this._memRepository = _memRepository;
}
}
I'll separate your question in half, one is base your current approach and better suitable one.
I realize that the goal you trying to achieve is to build a custom authentication challenge, and working alone or combine with the default one.
With your current approach:
The attribute wont work like that (you should give it parameter less constructor or just some constant flag to mark something special), otherwise, you won't get native DI. The compiler will yelling at you like this
Require constructor param right the moment you use it
If you want to keep your approach for the sake of simplicity, you will have to register your service first.
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IManageRepository, ManageRepository>();
}
You can register the service as singleton or scope depending on how you manually create your SqlConnection.
Then take the service out of the HttpContext like this:
public void OnAuthorization(AuthorizationFilterContext filterContext)
{
var manageRepository = filterContext.HttpContext.RequestServices
.GetRequiredService<IManageRepository>();
}
There you go... implement the rest of your logic.
A better approach:
Give authentication scheme a shot, then build a policy scheme to apply corresponding scheme for each Action or may be the whole controller.
This give you a central place to describe your authentication/authorization process in the app it's much clearer and highly adoptable with complex authentication requirement.
Combine this with redis rather than sqlConnection would be much better and scalable for production environment.

How to create an aspect decorator to handle EF transactions

I'm working (maintaining) on a dll assembly that acts as a Data Access Layer, there are many methods that requires transaction handling, many other do not, it's a currently "functional" dll, without any transaction handling method, I need to add it, so I'm looking for an easy way to add a transaction handler.
I'm wondering if is it possible to use AOP to create a decorator that I can add to the methods that requires a transaction.
I would like to have something like this:
[Transaction]
void MyDbMethod()
{
//DoSomething
myContext.SaveChanges();
}
For the EF model definition I'm using Code First, the current project uses Unity framework for some other DI tasks, can that framework be used for this?
If someone faces this same issue, I did not found any "by hand" solution, instead I used the PostSharp library and its OnMethodBoundaryAspect class, but be careful, at this moment the free/express license has limitations about the amount of classes where you can use it, so read carefully its limitations.
using System.Transactions;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace MyProject
{
[PSerializable]
public class Transaction : OnMethodBoundaryAspect
{
public Transaction()
{
//Required if the decorated method is async
ApplyToStateMachine = true;
}
public override void OnEntry(MethodExecutionArgs args)
{
//TransactionScopeAsyncFlowOption.Enabled => Required if the decorated method is async
var transactionScope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled);
args.MethodExecutionTag = transactionScope;
}
public override void OnSuccess(MethodExecutionArgs args)
{
var transactionScope = (TransactionScope)args.MethodExecutionTag;
transactionScope.Complete();
}
public override void OnExit(MethodExecutionArgs args)
{
var transactionScope = (TransactionScope)args.MethodExecutionTag;
transactionScope.Dispose();
}
}
}
You can do it using NConcern .NET AOP Framework.
This is an open source runtime AOP framework on which I actively work.
public class DataAccessLayer : IAspect
{
public IEnumerable<IAdvice> Advise(MethodInfo method)
{
//define how to rewrite method
yield return Advice.Basic.Arround(invoke =>
{
using (var transaction = new TransactionScope(...))
{
invoke(); //invoke original code
transaction.Complete();
}
});
}
}
Your business
public class MyBusiness
{
[Transaction]
void MyDbMethod()
{
}
}
Attach transaction scope aspect to you business
Aspect.Weave<DataAccessLayer>(method => method.IsDefined(typeof(TransactionAttribute), true);

Web API Exception Wrapper

I'm using WebAPI to call some third party methods:
public class SessionsController : ApiController
{
public DataTable Get(int id)
{
return Services.TryCall(es => es.GetSessionList(id).Tables[0]);
}
}
I'm wrapping all calls on this services:
internal static class Services
{
internal static IExternalService ExternalService { get; set; }
internal static T TryCall<T>(Func<IExternalService,T> theFunction)
{
try
{
return theFunction(ExternalService);
}
catch (FaultException<MyFaultDetail> e)
{
var message = new HttpResponseMessage(HttpStatusCode.NotImplemented);
message.Content = new StringContent(e.Detail.Message);
throw new HttpResponseException(message);
}
}
}
When an exception is thrown, it is caught and the message prepared. With rethrowing I get a new Error Message:
Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.
How can i return this exception properly, without Visual Studio complaining? When i skip the error, the browser gets an 501 error result.
The Method Request.CreateResponse() is not available in my wrapper method.
Well, while this may work, I recommend you creating an ExceptionFilterAttribute for this. This way, you won't have to guard every method for exception with the same bloated code.
For example:
public class FaultExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is FaultException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
}
}
}
There are several ways you can use this filter:
1. By Action
To apply the filter to a specific action, add the filter as an attribute to the action:
public class SampleController : ApiController
{
[FaultExceptionFilter]
public Contact SampleMethod(int id)
{
//Your call to a method throwing FaultException
throw new FaultException<MyFaultDetail>("This method is not implemented");
}
}
2. By Controller:
To apply the filter to all of the actions on a controller, add the filter as an attribute to the controller class:
[FaultExceptionFilter]
public class SampleController : ApiController
{
// ...
}
3. Globally
To apply the filter globally to all Web API controllers, add an instance of the filter to the GlobalConfiguration.Configuration.Filters collection. Exeption filters in this collection apply to any Web API controller action.
GlobalConfiguration.Configuration.Filters.Add(new FaultExceptionFilterAttribute());
If you use the "ASP.NET MVC 4 Web Application" project template to create your project, put your Web API configuration code inside the WebApiConfig class, which is located in the App_Start folder:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new FaultExceptionFilterAttribute());
// Other configuration code...
}
}

MVC global exceptions

I am coding an MVC 5 internet application, and I have a question in regards to handling exceptions globally.
I have my Application_Error setup in my global.asax file. This caters to errors such as 404 HttpExceptions.
How can I send all errors that occur in a controller to the Application_Error function? An example is the following exception:
System.Web.HttpRequestValidationException: A potentially dangerous
Request.Form value was detected from the client (name="").
I have written a OnException(ExceptionContext filterContext) for my controller, but am not sure on how to get the Application_Error function to handle these errors. Do I need to pass the exception from the OnException function, or is this the wrong approach?
Thanks in advance.
You can create a global filter by adding the following class to your App_Start folder:-
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
HandleErrorAttribute can be replaced with your own custom Exception Filter.
All you then need to do is make sure you add the following line of code to the App_Start method of your Gloabal.asax :-
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
//AreaRegistration.RegisterAllAreas();
//RouteConfig.RegisterRoutes(RouteTable.Routes);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}
}
Hope this helps.
I'm using some kind of http-module which gives me exactly what you are asking for:
public class MyModule : IHttpModule {
public void Init(HttpApplication context) {
context.Error += OnRequestError;
}
private void OnRequestError(object sender, EventArgs e) {
var context = ((HttpApplication)sender).Context;
var error = context.Error;
if (error == null)
return;
var errorType = error.GetType();
if (errorType == typeof(HttpException))
// do something
// this is what you are looking for
if (errorType = typeof(HttpRequestValidationException))
// do something, whatever you want
// works for me, so should work to you too
}
}
To get the module to work, you can use web.config or DynamicModuleHelper:
Install Microsoft.Web.Infrastructure and WebActivatorEx via nuget
Add a Bootstrapper class to your project
Register module at PreApplicationStartMethod
Sample:
// File: Bootstrapper.cs (contains class Bootstrapper)
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using WebActivatorEx;
using WhatEver.It.Is;
[assembly: PreApplicationStartMethod(typeof(Bootstrapper), "Bootstrap")]
namespace WhatEver.It.Is {
public class Bootstrapper {
public static void Bootstrap() {
// Do what do you need just before the application get started
// like registering modules, etc...
DynamicModuleUtility.RegisterModule(typeof(MyModule));
}
}
}

WebApi's custom exception when "does not support http method"

I have a simple controller :
public class UsersController : ApiController
{
[HttpPost]
[AllowAnonymous]
public HttpResponseMessage Login([FromBody] UserLogin userLogin)
{
var userId = UserCleaner.Login(userLogin.MasterEntity, userLogin.UserName, userLogin.Password, userLogin.Ua);
if (userId == null) return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "User not authorized");
return Request.CreateResponse(HttpStatusCode.OK, Functions.RequestSet(userId));
}
}
As you can see , only POST is currently available .
But when I invoke a GET in a browser (just for checking):
http://royipc.com:88/api/users
I get :
{"Message":"The requested resource does not support http method
'GET'."}
It is clear to me why it happens. But I want to return a custom exception when it happens.
Other answers here at SO doesn't show how I can treat this kind of situation (not that i've found of, anyway)
Question
How (and where) should I catch this kind of situation and return custom exception (HttpResponseMessage) ?
NB
I don't want to add a dummy GET method just for "catch and throw". tomorrow there can be a GET method. I just want to catch this Exception and return my OWN !
You may need to inherit from ApiControllerActionSelector class which is what the Web API uses to select the required action.
then you can replace the default IHttpActionSelector by your new action selector like that. config.Services.Replace(typeof(IHttpActionSelector), new MyActionSelector());
check this url for full example: http://www.strathweb.com/2013/01/magical-web-api-action-selector-http-verb-and-action-name-dispatching-in-a-single-controller/
You can build custom Exception filters in ASP.Net WebAPI. An exception filter is a class that implements the IExceptionFilter interface. To create a custom exception filter you can either implement the IExceptionFilter interface yourself or create a class that inherits from the inbuilt ExceptionFilterAttribute class. In the later approach all you need to do is override the OnException() method and plug-in some custom implementation.
public class MyExceptionFilter:ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
HttpResponseMessage msg = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent("An unhandled exception was thrown by the Web API controller."),
ReasonPhrase = "An unhandled exception was thrown by the Web API controller."
};
context.Response = msg;
}
}
you would likely want to test for conditions and generate the exact exception, but this is a bare example.
To use the exception class, you can either register it in the Global.asax, or as an attribute on a specific class or method.
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configuration.Filters.Add(new WebAPIExceptionsDemo.MyExceptionFilter());
AreaRegistration.RegisterAllAreas();
...
}
}
or
[MyExceptionFilter]
public class UsersController : ApiController
{
...
}

Categories