I am trying to create a more robust method that returns two different object types depending on results.
If the result is negative then return CustomError object, but if the result is positive then return Auto object.
Example below to demonstrate.
AutoService.cs
public class AutoService {
public async Task<object> Create(NewAuto model)
{
var auto = new Auto {
Type = model.Type,
Year = model.Year,
// other parameters
}
try {
await _autoDb.Create(auto);
}
catch (Exception e) {
// return this error object if something broken
return new CustomError { Message = "It is broken" }
}
//return the Auto entity if successful
return auto;
}
}
CustomError.cs
public class CustomError {
public string Message {get;set;}
}
In the current format the when calling Create method i will need to cast the result which brings headaches of its own (cast against CustomError or Auto class for e.g.).
Any advice how i can do this properly?
Why not create a class to represent the result, something like:
class EntityResult<T> {
public EntityResult(T entity) {
Success = true;
Entity = entity;
}
public EntityResult(string error) {
Success = false;
Error = error;
}
bool Success {get; }
T Entity { get; }
string Error { get; }
}
Usage would be like:
public async Task<EntityResult<Auto>> Create(NewAuto model) {
var auto = new Auto {
Type = model.Type,
Year = model.Year,
// other parameters
};
try {
await _autoDb.Create(auto);
return new EntityResult(auto);
} catch (Exception e) {
// return this error object if something broken
return new EntityResult<Auto>("Error goes here");
}
}
I wouldn't use a return type to represent two different results e.g. success and failure. It will make the code hard to understand and, as time goes on, you will (probably) find that the return type will get abused and expanded to contain other (irrelevant?/unnecessary?) information.
Apply the Single Responsibility Principle to the return type:
If the call was successful then return the correct object i.e. Auto
If the call failed (i.e. you caught and exception) then create a custom exception to pass that failure back up the call stack. The name of your exception will make the code clearer than enclosing errors in a generic object.
Also your calling code will be much cleaner (and easier to maintain) if you use exception handling instead of an object with two purposes. Keep it simple.
Related
I am currently developing an API and need to return some objects for the api or an error in case of failure somewhere, mainly because I am dependent on database calls.
Here is some of my code:
public Student GetStudent(string parametr)
{
try
{
// Database call 1
// Database call 2
return new Student();
}
catch (Exception ex)
{
// return new ErrorDetails(ex.message); -- example
return null;
}
}
One of my constraints is that I need to put this API in swagger. I tried with HttpResponse which fits perfectly my needs regarding the coding part, but that does not work with swagger. My web application is not asp.net core.
Any ideas or suggestions on what should I do?
Thanks in advance,
You can use Swagger DataAnnotations and encapusulate the return data to achieve that
First of all create a class to encapsulate the error messages like that
public class Errors
{
public List<string> ErrorMessages { get; set; } = new List<string>();
}
Then use the annotaions like that
For .NET 4.5+ (Fullframework)
[SwaggerResponse(HttpStatusCode.OK, Type = typeof(Student))]
[SwaggerResponse(HttpStatusCode.BadRequest, Type = typeof(Errors))];
public IHttpActionResult GetStudent(string parametr)
{
try
{
// Database call 1
// Database call 2
return Ok(new Student());
}
catch (Exception ex)
{
Errors errors = new Errors();
errors.ErrorMessages.Add(ex.Message);
return Content(HttpStatusCode.BadRequest, errors);
}
}
For .NET Core
[ProducesResponseType(200, Type = typeof(Student))]
[ProducesResponseType(400, Type = typeof(Errors))]
public IActionResult GetStudent(string parametr)
{
try
{
// Database call 1
// Database call 2
return Ok(new Student());
}
catch (Exception ex)
{
Errors errors = new Errors();
errors.ErrorMessages.Add(ex.Message);
return BadRequest(errors);
}
}
Note that the BadRequest is just an example of return, you should always return the correct Http Status Code message, like 404 to not found, 401 to forbidden and so on
What is a good way to bubble up a DbUpdateConcurrencyException to the view from the grain?
I'm currently working on an Orlean's prototype that has a custom state that I'm using Entity Framework Core to communicate with the DB and using the optimistic concurrency patterns built into EF Core to manage the concurrency issues.
Where I'm having an issue is that I want to bubble up my Exception from the grain to the view and am not receiving it on the view end.
I'm trying to accomplish this because I want to deal with some of the concurrency issues that are more pressing on the view so that the user can decide or at least be alerted to the issue.
I brought this up on the Orlean's Gitter, but didn't get many ideas from it.
Example of my code for updating:
public Task UpdateUser(User user)
{
//Reason for second try/catch is to bubble the error to controller
try
{
userState = new User
{
Username = this.GetPrimaryKeyString(),
accountType = user.accountType,
FName = user.FName,
LName = user.LName,
RowVersion = user.RowVersion,
CreatedDate = user.CreatedDate
};
UpdateState();
}
catch (DbUpdateConcurrencyException ex)
{
throw ex;
}
return Task.CompletedTask;
}
public Task UpdateState()
{
using (var context = new OrleansContext())
{
context.users.Update(userState);
try
{
context.SaveChanges();
}
catch ( DbUpdateConcurrencyException ex)
{
var entry = ex.Entries.Single();
var clientValues = (User)entry.Entity;
var databaseEntry = entry.GetDatabaseValues();
//Make sure the row wasn't deleted
if(databaseEntry != null)
{
var databaseValues = (User)databaseEntry.ToObject();
if(clientValues.accountType != databaseValues.accountType)
{
//Bubble up the exception to controller for proper handling
throw ex;
}
//Update Row Version to allow update
userState.RowVersion = databaseValues.RowVersion;
context.SaveChanges();
}
}
}
return Task.CompletedTask;
}
I'm open to any suggestions on this as long as it allows the user to be alerted to the Exception and can view their data and the current DB values.
There is a chance that the exception is not being serialized or deserialized correctly. The primary reasons for this could be:
The Exception class does not correctly implement the ISerializable pattern.
The assembly which contains the Exception class is not present on the client, so the client does not understand how to create the Exception type.
In this case, I would lean towards the second reason, because most (but not all!) Exception classes do correctly implement the ISerializable pattern.
In either case, you can catch your exception and turn it into a generic exception.
You could create a helper method to do this using the LogFormatter.PrintException(Exception) method from Orleans to format the exception as a string.
public static void ThrowPlainException(Exception e) =>
throw new Exception(Orleans.Runtime.LogFormatter.PrintException(e));
The solution I came to was to create a custom exception class that serializable add the database values object to it and bubble that up to the views.
[Serializable]
public class UpdateException : Exception
{
public object databaseValues { get; set; }
public UpdateException(object databaseValues)
{
this.databaseValues = databaseValues;
}
public UpdateException(string message, object databaseValues) :base(message)
{
this.databaseValues = databaseValues;
}
}
I know the normal programming. But now I would like to implement interfaces.
My question is if I have an MVC architecture what should an interface have only the controller or the models?
Why an interface? Since I should develop a controller for another company and they should be able to use the methods so empty.
If the models should also have an interface, how does the add with EntityFramework get this error:
public async Task<Result> CreateOrderingEquipmentAsync(IOrderingEquipment orderingEquipment)
{
var result = new Result();
if (!ModelStateIsValid(orderingEquipment))
{
return BadRequest(orderingEquipment);
}
if (await GetOrderingEquipmentAsync(orderingEquipment.Guid) != null)
{
return AlreadyExist(orderingEquipment.Guid);
}
try
{
orderingEquipment.Timestamp = DateTime.UtcNow;
_context.OrderingEquipments.Add(orderingEquipment);
await _context.SaveChangesAsync();
result = CreatedResult(orderingEquipment);
}
catch (Exception e)
{
Log.Error(e);
if (e.InnerException != null)
{
Log.Error(e.InnerException.Message);
}
}
return result;
}
Your add method accepts an object of type OrderingEquipment but your variable is of type IOrderingEquipment.
Try casting it using the "as" keyword, then, after having checked for null, pass the newly created variable to your method.
I know this question has already been asked but I couldn't find an answer that satisfied me. What I am trying to do is to retrieve a particular DbSet<T> based on its type's name.
I have the following :
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyDllAssemblyName")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyCallingAssemblyName")]
class MyDbContext : DbContext {
public DbSet<ModelA> A { get; set; }
public DbSet<ModelB> B { get; set; }
public dynamic GetByName_SwitchTest(string name) {
switch (name) {
case "A": return A;
case "B": return B;
}
}
public dynamic GetByName_ReflectionTest(string fullname)
{
Type targetType = Type.GetType(fullname);
var model = GetType()
.GetRuntimeProperties()
.Where(o =>
o.PropertyType.IsGenericType &&
o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) &&
o.PropertyType.GenericTypeArguments.Contains(targetType))
.FirstOrDefault();
if (null != model)
return model.GetValue(this);
return null;
}
}
I have no trouble getting the type itself whether it is via a simple switch or reflection. I need however to return the type as a dynamic since I do not know what DbSet type it will be.
Then somewhere else in the same assembly, I use it this way :
// MyDbContext MyDbContextInstance..
var model = MyDbContextInstance.GetByName_SwitchTest("A");
var record1 = model.FirstOrDefault(); // It crashes here with RunTimeBinderException
At this point model contains an instance of a InternalDbSet<ModelA> type. From there, any use I do with the model object I get a RunTimeBinderException :
'Microsoft.Data.Entity.Internal.InternalDbSet' does not contain a definition for 'FirstOrDefault'
Investigating on the web, I found a blog post explaining that (dixit his blog) :
the reason the call to FirstOrDefault() fails is that the type
information of model is not available at runtime. The reason it's not
available is because anonymous types are not public. When the method
is returning an instance of that anonymous type, it's returning a
System.Object which references an instance of an anonymous type - a
type whose info isn't available to the main program.
And then he points that a solution :
The solution is actually quite simple. All we have to do is open up
AssemplyInfo.cs of the ClassLibrary1 project and add the following
line to it: [assembly:InternalsVisibleTo("assembly-name")]
I did try this solution on my code but it doesn't work. For info I have an asp.net 5 solution with two assemblies running on dnx dotnet46. An app and a dll containing all my models and DbContext. All the concerned calls I do are located on the dll though.
Does this solution have any chance to work ?
Am I missing something ?
Any pointers would be greatly appreciated ?
Thanks in advance
[EDIT]
I have tried to return IQueryable<dynamic> rather than dynamic and I could do the basic query model.FirstOrDefault(); but above all I'd like to be able to filter on a field too :
var record = model.FirstOrDefault(item => item.MyProperty == true);
So how did I do it when I am not aware of <T> during compile time.
First need to get the type as DbContext.Set method returns a non-generic DbSet instance for access to entities of the given type in the context and the underlying store.
public virtual DbSet Set(Type entityType)
Note here argument is the type of entity for which a set should be returned.And set for the given entity type is the return value.
var type = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.Name == <Pass your table name>);
now once I have this type
if(type != null)
{
DbSet context = context.Set(type);
}
Or a one liner would be
DbSet mySet = context.Set(Type.GetType("<Your Entity Name>"));
*Disclaimer: This response doesn't give a stricto sensu answer to my question. It is rather a different approach to resolve my own problem. I am aware this is a specific example for a given situation that will not work for everyone. I am posting this approach in the hope it helps someone but will not mark it as the answer as I am still hoping for a real solution.
To start with, let's accept the fact that the only useful information we can get out of the current code is whether a record exists or not.. Any attempt of a dynamic queries after that would give the RuntimeBinderException.
Then let's continue with another fact; DbContext.Add(object) and DbContext.Update(object) are not template based so we can use them to save our models ( Instead of db.A.Add() or db.A.Update() )
In my own situation, no more is required to work out a procedure
Define models a little differently
To start with, I need a field that is retrievable across all my models which should obviously be a way to identify a unique record.
// IModel give me a reliable common field to all my models ( Fits my DB design maybe not yours though )
interface IModel { Guid Id { get; set; } }
// ModelA inherit IModel so that I always have access to an 'Id'
class ModelA : IModel {
public Guid Id { get; set; }
public int OtherField { get; set; }
}
// ModelB inherit IModel so that I always have access to an 'Id'
class ModelB : IModel {
public Guid Id { get; set; }
public string WhateverOtherField { get; set; }
}
Re-purpose the dynamic queries a bit to do something we know works
I haven't found a way to do smart query dynamically, so instead I know I can reliably identify a record and know if it exists or not.
class MyDbContext : DbContext {
public DbSet<ModelA> A { get; set; }
public DbSet<ModelB> B { get; set; }
// In my case, this method help me to know the next action I need to do
// The switch/case option is not pretty but might have better performance
// than Reflection. Anyhow, this is one's choice.
public bool HasRecord_SwitchTest(string name) {
switch (name) {
case "A": return A.AsNoTracking().Any(o => o.Id == id);
case "B": return B.AsNoTracking().Any(o => o.Id == id);
}
return false;
}
// In my case, this method help me to know the next action I need to do
public bool HasRecord_ReflectionTest(string fullname)
{
Type targetType = Type.GetType(fullname);
var model = GetType()
.GetRuntimeProperties()
.Where(o =>
o.PropertyType.IsGenericType &&
o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) &&
o.PropertyType.GenericTypeArguments.Contains(targetType))
.FirstOrDefault();
if (null != model)
return (bool)model.GetValue(this).AsNoTracking().Any(o => o.Id == id);
return false;
}
// Update and save immediately - simplified for example
public async Task<bool> UpdateDynamic(object content)
{
EntityEntry entry = Update(content, GraphBehavior.SingleObject);
return 1 == await SaveChangesAsync(true);
}
// Insert and save immediately - simplified for example
public async Task<bool> InsertDynamic(object content)
{
EntityEntry entry = Add(content, GraphBehavior.SingleObject);
return 1 == await SaveChangesAsync(true);
}
}
A little bit of plumbing to give a sense to my situation
Next, what I needed to do with that dynamic queries was a way to replicate data from a server down to my client. ( I have omitted a big chunk of the architecture to simplify this example )
class ReplicationItem
{
public ReplicationAction Action { get; set; } // = Create, Update, Delete
public string ModelName { get; set; } // Model name
public Guid Id { get; set; } // Unique identified across whole platform
}
Connecting the bits.
Now, here's the routine that connects the bits
public async void ProcessReplicationItem(ReplicationItem replicationItem)
{
using (var db = new MyDbContext())
{
// Custom method that attempts to get remote value by Model Name and Id
// This is where I get the strongly typed object
var remoteRecord = await TryGetAsync(replicationItem.ModelName, replicationItem.Id);
bool hasRemoteRecord = remoteRecord.Content != null;
// Get to know if a local copy of this record exists.
bool hasLocalRecord = db.HasRecord_ReflectionTest(replicationItem.ModelName, replicationItem.Id);
// Ensure response is valid whether it is a successful get or error is meaningful ( ie. NotFound )
if (remoteRecord.Success || remoteRecord.ResponseCode == System.Net.HttpStatusCode.NotFound)
{
switch (replicationItem.Action)
{
case ReplicationAction.Create:
{
if (hasRemoteRecord)
{
if (hasLocalRecord)
await db.UpdateDynamic(remoteRecord.Content);
else
await db.InsertDynamic(remoteRecord.Content);
}
// else - Do nothing
break;
}
case ReplicationAction.Update:
[etc...]
}
}
}
}
// Get record from server and with 'response.Content.ReadAsAsync' type it
// already to the appropriately
public static async Task<Response> TryGetAsync(ReplicationItem item)
{
if (string.IsNullOrWhiteSpace(item.ModelName))
{
throw new ArgumentException("Missing a model name", nameof(item));
}
if (item.Id == Guid.Empty)
{
throw new ArgumentException("Missing a primary key", nameof(item));
}
// This black box, just extrapolate a uri based on model name and id
// typically "api/ModelA/{the-guid}"
string uri = GetPathFromMessage(item);
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:12345");
HttpResponseMessage response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
return new Response()
{
Content = await response.Content.ReadAsAsync(Type.GetType(item.ModelName)),
Success = true,
ResponseCode = response.StatusCode
};
}
else
{
return new Response()
{
Success = false,
ResponseCode = response.StatusCode
};
}
}
}
public class Response
{
public object Content { get; set; }
public bool Success { get; set; }
public HttpStatusCode ResponseCode { get; set; }
}
ps: I am still interested in a real answer, so please keep posting for other answer if you have a real one to share.
You could use this to get the DBSet for a specific type:
public object GetByType(DbContextcontext, Type type) {
var methode = _context.GetType().GetMethod("Set", types: Type.EmptyTypes);
if (methode == null) {
return null;
}
return methode.MakeGenericMethod(type).Invoke(_context, null);
}
I have my own wcf service class which should as result return string with "Everything Save Saccesfully" if ok save data. Otherwise I need to return in this string exception.
string SaveData(Stream stream)
{
string error = "";
try
{
//do saving data
error+="Everything Save Saccefully";
return error;
}
catch(Exception ex)
{
throw ex;
}
finally
{
}
}
It is possible to catch errors occurs in try block and return it in error variable ?
Well, the traditional way that you express the error is simply via an exception - not a return value. Lack of exception should imply "everything went correctly". That's the normal idiomatic way of working.
Now, occasionally it's worth having a method which doesn't throw an exception, but instead returns a success status and potentially a separate result via an out parameter. But that's relatively rare - it's usually for things like parsing, where it's entirely normal for it to fail in hard-to-predict ways when nothing's really wrong other than the input data.
In your case, it looks like this should be a void method which simply throws an exception on error.
Normally I would do as suggested by Jon, but if you really don't want to allow any exceptions to bubble up from your service you could encapsulate your success and (any) failure error information in a class structure like this
public class ErrorInfo
{
public string Message {get; set;}
// TODO: Maybe add in other information about the error?
}
public class SaveResult
{
public bool Success { get; set; }
/// <summary>
/// Set to contain error information if Success = false
/// </summary>
public ErrorInfo ErrorInfo { get; set; }
}
And then...
public SaveResult SaveData(Stream stream)
{
SaveResult saveResult = new SaveResult();
string error = "";
try
{
//do saving data
saveResult.Success = true;
}
catch (Exception ex)
{
saveResult.ErrorInfo = new ErrorInfo { Message = ex.Message };
}
}
The downside of this approach is that your caller must check the Success value after calling SaveData. Failure to do so can result in a bug in your code that will only manifest itself if the save fails.
Alternatively, if you don't handle the exception you get to benefit from one of the useful things about structured exception handling: If the caller forgets to explicitly handle any exception then it will bubble up the call stack and either crash the app or get caught by some higher-level error handling code.
Not necessarily ideal, but generally better than your code silently assuming that something succeeded, when in fact it didn't.
You should use Faults for exceptional results in WCF. I do not see idea why you would need exception in string. But if you absolutely need this, just move return statement to the end and set its value in catch block too.
string SaveData(Stream stream)
{
string error = "";
try
{
//do saving data
error+="Everything Save Saccefully";
}
catch(Exception ex)
{
//throw ex; Do not throw, just return its string representation
error+=ex.ToString();
}
finally
{
}
return error;
}
Try this :
string SaveData(Stream stream)
{
string error;
try
{
//do saving data
error ="Everything saved Successfully";
}
catch(Exception ex)
{
error = ex.Message;
}
return error;
}