custom exception for null parameters in c# - c#

I'm trying to create custom exceptions for a Web-API program, if the name, code or whatever is null, it should send me a custom message saying x input is empty or null error, I'm not sure how to finish it so I'd appreciate some help.
public Product CreateProduct(Product p)
{
if (p.Name.Trim() == "")
{
throw new InvalidProductDataException("El producto no tiene nombre");
}
return p;
}

I'm assuming CreateProduct is an action method on a Controller class, and what you are actually trying to do is return errors to a client that is calling your API. Therefor, the easiest way to return errors to an HTTP client is by using the IActionResult return type instead of returning your actual type. This will give you control over the HTTP status code.
class ProductController : Controller {
public IActionResult CreateProduct(Product p)
{
if (String.IsNullOrWhitespace(p.Name))
{
return BadRequest("El producto no tiene nombre");
}
// Perform create?
return Ok(p);
}
}
For more information on controller action return types see: https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-5.0
Any kind of exception thrown from a controller action is going to result in an opaque HTTP 500 response sent to the API client, which probably isn't what you want for this kind of error.
An alternative is to introduce Middleware that will capture certain types of exception and convert them to HTTP responses.

Let's define a custom exception named LoginException that will be used to throw an error exception in login processes.
public class LoginException : System.Exception
{
//todo
}
Now let's make the necessary constructor definitions for use in the application.
public class LoginException : System.Exception
{
public LoginException()
: base()
{ }
public LoginException(String message)
: base(message)
{ }
public LoginException(String message, Exception innerException)
: base(message, innerException)
{ }
protected LoginException(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
}
As seen above, we have defined the constructors of LoginException and made the constructor redirects for the System.Exception class, so we made the LoginException class ready for use.
void Login(string userName, string password)
{
try
{
if (userName != "canert" && password != "qwerty123")
throw new LoginException("Invalid login operation");
}
catch (LoginException loginException)
{
Response.Write(loginException.Message);
}
}

If you want to throw a custom type of exception called InvalidProductDataException then you need to declare a class with that name and it needs to be a subclass of System.Exception:
public class InvalidProductDataException : System.Exception {
public InvalidProductDataException(String message) : base(message) {
}
// This constructor overload is necessary to allow for your Exception to be deserialized. This is a best practice when implementing custom Exception types.
protected InvalidProductDataException(SerializationInfo info, StreamingContext context) :
base(info, context) {
// If you exception contained custom properties, you would want to deserialize them here
}
}
For more information on creating custom Exception classes see: https://learn.microsoft.com/en-us/dotnet/standard/exceptions/how-to-create-user-defined-exceptions
Note: It is not necessary to create a custom Exception class just to be able to specify the message that you want. For example you could simply throw new Exception("your message"). However it does make sense to create a custom Exception class if you want to be able to catch that specific exception elsewhere in your code.

Related

Exception Attribute for Class library

My service class has many methods, which call other service and this service has specified exceptions. I want to throw my exception when method catch this specified exception.
I.e.
try
{
// call other service
}
catch(ServiceXxxException serviceEx)
{
throw new MyException(...);
}
but I have many such methods and I don't want to grow code. Is it possible to create exception attribute like ExceptionFilterAttribute for ASP.NET MVC/Core ?
You can create general filter to handle any exception may occur and you can use filter attribute to handle, you can use it within the controller or action, something like this :
CustomExceptionFilter]
public class HomeController:Controller
{
//......
}
//Over the Action
[CustomExceptionFilter]
public ActionResult Index()
{
//.......
}
please follow this article :
https://www.c-sharpcorner.com/UploadFile/0ef46a/exception-filters-in-mvc/

ASP.NET Core Exception middelware nesting exceptions for each layer

I created a global Exception handler middelware to catch all my custom exceptions.
When throwing an Exception in my DAL I expect that the middelware will catch it as the same type that it was thrown.
// API
[HttpGet]
[Route("api/users")]
public IActionResult Get(int id)
{
var user = _userService.GetById(id);
return Ok(user);
}
// Repository
public async Task<List<User>> GetById(int id)
{
throw new EntityNotFoundException("code", "message");
// .. return user
}
// Exception handler
public async Task Invoke(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex) // ex is of type JsonSerializationException
{
if (ex is EntityNotFoundException)
{
// Handle exception
}
}
}
In the above example the Exception is handled but is of type JsonSerializationException with an InnerException of type System.AggregateException that contains another InnerException with type EntityNotFoundException.
It seems that the Exception gets nested for each layer it gets passed along (DAL > Service > API). How can I avoid this so that I can catch the Exception as the original type?
The example you provided looks good but it lacks one important thing, which is single responsibility.
ASP.NET Core has a better approach, which is using exception filters, that can be registered globally too and can be written for each custom-exception and even for unhandled exceptions.
Sample:
public class EntityNotFoundExceptionFilter : IExceptionFilter
{
public EntityNotFoundExceptionFilter(// some dependencies that u want to inject)
{
...
}
public void OnException(ExceptionContext context)
{
if (!(context.Exception is EntityNotFoundException))
{
return;
}
context.ExceptionHandled = true;
context.Result = new NotFoundObjectResult // will produce 404 response, you can also set context.HttpContext.Response.StatusCode based on your exceptions statuscode and return an ObjectResult instead
{
context.Exception.Message
}
}
}
Now in your Startup.cs in the ConfigureServices(...) function add the following
public void ConfigureService(IServiceCollection services)
{
...
services.AddMvc(options =>
{
...
options.Filters.Add(typeof(EntityNotFoundExceptionFilter));
...
}
...
}
You will end up writing many filters but it is a cleaner approach and that is how the asp.net-core filterpipeline should be used + this will be working :)
I am not 100% sure why there are so many exceptions in your current implementation but my guess is that asp.net tries to return the exception and then fails to serialize it and stuff like that.
Edit:
I create a minimal example that can be found here. Just access the url via http://localhost:58741/api/some after cloning the project.

Handle exceptions / HTTP status code based on exception types

I'm trying to throw some exception, catch it in a HandleException attribute and return it properly to the client.
Here is an example:
[HandleException(Type = typeof(UserNotFoundException), Status = HttpStatusCode.NotFound)]
[HandleException(Type = typeof(LoginFailedException), Status = HttpStatusCode.Unauthorized)]
public UserProfile Login(UserCredentials userCred)
In my Login() function I either throw a UserNotFoundException or LoginFailedException.
My HandleExceptionAttribute looks like this:
public class HandleExceptionAttribute : ExceptionFilterAttribute
{
public Type Type { get; set; }
public HttpStatusCode Status { get; set; }
public override void OnException(HttpActionExecutedContext context)
{
var ex = context.Exception;
ResponseHelper.CreateException(Status, ex.Message);
}
}
What I want is to be able to handle what kind of exceptions is going to be thrown and handle it properly in an attribute, where I specify the HttpStatusCode.
The problem, with this code, is that the top-most attribute is always called. So even if the exception is a LoginFailedException I always get UserNotFoundException and 404 code returned to the client.
How can I achieve this?
Just off the top of my head, it looks like you're going to need to do some filtering in your OnException method, so that you verify that the exception you got matches the exception you intended that instance of the attribute to handle.
public override void OnException(HttpActionExecutedContext context)
{
var ex = context.Exception;
if(typeof(ex) == Type)
ResponseHelper.CreateException(Status, ex.Message);
}

How to display my own exception?

I'm developing a web project where i need to add custom exception classes. For example, how can i display a message from my custom exception class when the session timeout occurs? Please help. Any sample will be helpful.
This is what i written in my exception class so far:
public class CustomException : Exception
{
private string message;
public CustomException ()
{
this.message = "Invalid Query";
}
public CustomException (String message)
{
this.message = message;
}
}
Need to know how to link this with the session timeout, from where i need to write the logic of the same. Thank You.
If you are looking to throw your custom exception when the is raised you can do it like this.
try {
DataTable dt = q.ExecuteQuery(); //This throws a timeout.
} catch(SessiontTimeoutException ste) {
throw new CustomException("Session has timed out");
} catch(Exception e) {
//Show unexpected exception has occured
}
Not too sure if this is what you are trying to do.
Update:
To Find out if SqlException is a TimeoutException please see this StackOverFlow Post.
You might want to write this as
public CustomException() : base("Invalid Query") { }
this way the exception message gets passed correctly, for the other constructor
public CustomException(String message) : base(message) { }
then you don't need the private string message field.
SqlException class exposes the property Errors which is a collection of SqlError objects. You can query the Number property of each error object which corresponds to an entry in the master.dbo.sysmessages table.
I recommend you use Inner Exception to get user friendly exception message with also the system error message. If getting MyException, you'll see your exception message and the system exception message at MyException.ToString().
Additionally, if you are concerned for coding Exception, you can use the Code Snippet Feature of VS. Just type 'Exception' and press TAB key twice, then VS will create Exception class as the following code.
try
{
DataTable dt = q.ExecuteQuery(); //This throws a timeout.
}
catch (SessiontTimeoutException ex)
{
throw new MyException("my friendly exception message", ex);
}
[Serializable]
public class MyException : Exception
{
public MyException() { }
public MyException(string message) : base(message) { }
public MyException(string message, Exception inner) : base(message, inner) { }
protected MyException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}

Handling exceptions in a N Tier, Domain Driven Design, MVC application

I've built an MVC application that looks like this:
MVC Application - Application Layer - Business Layer - Repository - Data
I've read the code of many applications and discovered that no-one seems to pass exceptions in manner similar to how data is passed.
In other words, data is referenced through an interface and reused in different contexts. If an exception occurs in the Data layer, how would this get sent to the GUI or relevant layer? Should an Interface be used? What is the construct for handling exceptions in this application?
I haven't read the doco u linked but i have a simple case where i raise exceptions in response to failure to satisfy an invariant. Say I'm creating an instance and it's "invalid" for some reason, let's say bad user input. Rather than having my entity be in an invalid state (which is a no-no in DDD) and let the system "validate" it, it throws an exception when it's being created. The relevant "validation messages" (for the user) are extracted from the same Specification instance that was not satisfied and my derived exception contains the values the UI needs.
Example of an InvariantException:
public class InvariantException : MyAppException
{
public object FailingObject = null;
public ModelStateDictionary ModelState = new ModelStateDictionary();
public InvariantException() { }
public InvariantException(object failingObject, ModelStateDictionary messages)
{
this.FailingObject = failingObject;
this.ModelState = messages;
}
public InvariantException(object failingObject, ModelStateDictionary messages,
Exception innerException)
: base("refer to ModelState", innerException)
{
this.FailingObject = failingObject;
this.ModelState = messages;
}
}
Example of a Specification that returns the relevant "validation messages" for the user/UI:
public class PostFieldLengthSpecification : ISpecification<Post>
{
private const string TITLE_LENGTH_RANGE = "5-100";
private const string BODY_LENGTH_RANGE = "20-10000";
public bool IsSatisfiedBy(Post post)
{
return this.GetErrors(post).IsValid;
}
public ModelStateDictionary GetErrors(Post post)
{
ModelStateDictionary modelState = new ModelStateDictionary();
if (!post.Title.Trim().Length.Within(TITLE_LENGTH_RANGE))
modelState.AddModelError(StongTypeHelpers.GetPropertyName((Post p) => p.Title),
"Please make sure the title is between {0} characters in length".With(TITLE_LENGTH_RANGE));
if (!post.BodyMarkup.Trim().Length.Within(BODY_LENGTH_RANGE))
modelState.AddModelError(StongTypeHelpers.GetPropertyName((Post p) => p.BodyMarkup),
"Please make sure the post is between {0} characters in length".With(BODY_LENGTH_RANGE));
return modelState;
}
}
Example of how the Factory never let's the invalid instance be created, instead it throws an exception and deposits the messages for the UI:
public static Post GetNewPost(string title, string bodyMarkup, DateTime posted)
{
var post = new Post(0, title, bodyMarkup, posted, new List<Comment>());
var fieldLengthSpec = new PostFieldLengthSpecification();
if (fieldLengthSpec.IsSatisfiedBy(post))
return post;
else
throw new InvariantException(post, fieldLengthSpec.GetErrors(post));
}
Finally, an example of a custom model binder that is used to catch said exception and pass the "invalid object" back to the action with the error messages:
public class PostModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType == typeof(Post))
{
try
{
// Create Post
return base.BindModel(controllerContext, bindingContext);
}
catch (InvariantException ie)
{
// If invalid, add errors from factory to ModelState
bindingContext.ModelState.AddNewErrors(ie.ModelState);
bindingContext.ModelState.AddValuesFor<Post>(bindingContext.ValueProvider);
return ie.FailingObject;
}
}
Hope this helps.

Categories

Resources