Entity Framework with Interface - c#

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.

Related

ASP.NET WebApi return different object on exception

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

Handling errors and success in same format

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.

Typewriter ReturnType from IActionResult

I have started to play around with Typewriter to see if it would fit my requirements for generating both Models and an API layer.
So far, it is working for generating models, and I have it generating some sort of API Layer, however I have run into a snag when using the $ReturnType as demonstrated in the example Angular Web API Service. In the example code;
${
using Typewriter.Extensions.WebApi;
string ReturnType(Method m) => m.Type.Name == "IHttpActionResult" ? "void" : m.Type.Name;
string ServiceName(Class c) => c.Name.Replace("Controller", "Service");
}
module App { $Classes(:ApiController)[
export class $Name {
constructor(private $http: ng.IHttpService) {
} $Methods[
public $name = ($Parameters[$name: $Type][, ]) : ng.IHttpPromise<$ReturnType> => {
return this.$http<$ReturnType>({
url: `$Url`,
method: "$HttpMethod",
data: $RequestData
});
};]
}
angular.module("App").service("$ServiceName", ["$http", $Name]);]
}
It is using $ReturnType, however when you are calling a .net WebApi controller with the method;
public async Task<IActionResult> DoSomething(){
return Ok(MyModel);
}
The $ReturnType is IActionResult, which is not strongly typed enough for me. I want this to be of type MyModel.
Is there something I can do to get the type returned within Ok? Can I decorate the method with a Type which Typewriter can then read and use?
Ok, so I have had no answers on this question, so I will answer it with my current solution so it might help out others.
I have created a new Attribute;
public class ReturnTypeAttribute : Attribute
{
public ReturnTypeAttribute(Type t)
{
}
}
Which I then use to decorate my Api method;
[ReturnType(typeof(MyModel))]
public async Task<IActionResult> DoSomething(){
return Ok(MyModel);
}
Now in my TypeWriter file, I have the following code;
string ReturnType(Method m) {
if (m.Type.Name == "IActionResult"){
foreach (var a in m.Attributes){
// Checks to see if there is an attribute to match returnType
if (a.name == "returnType"){
// a.Value will be in the basic format "typeof(Project.Namespace.Object)" or "typeof(System.Collections.Generic.List<Project.Namespace.Object>)
// so we need to strip out all the unwanted info to get Object type
string type = string.Empty;
// check to see if it is an list, so we can append "[]" later
bool isArray = a.Value.Contains("<");
string formattedType = a.Value.Replace("<", "").Replace(">", "").Replace("typeof(", "").Replace(")", "");
string[] ar;
ar = formattedType.Split('.');
type = ar[ar.Length - 1];
if (isArray){
type += "[]";
}
// mismatch on bool vs boolean
if (type == "bool"){
type = "boolean";
}
return type;
}
}
return "void";
}
return m.Type.Name;
}
So as you can see, I am checking for an Attribute called "returnType", then getting the value of this attribute which is a string, removing some formatting to get to the raw object name, then returning this. So far it is working well for my needs. If anyone can think of a nicer solution, then please let me know!
It is not the best solution I was hoping for as you need to make sure you have ReturnType(typeof(Object)) if you want the correct type in the .ts file.
In my case I get the return type from the parameter in the method:
// Turn IActionResult into void
string ReturnType(Method objMethod)
{
if(objMethod.Type.Name == "IActionResult")
{
if((objMethod.Parameters.Where(x => !x.Type.IsPrimitive).FirstOrDefault() != null))
{
return objMethod.Parameters.Where(x => !x.Type.IsPrimitive).FirstOrDefault().Name;
}
else
{
return "void";
}
}
else
{
return objMethod.Type.Name;
}
}
See:
Turbocharging Your Angular 4+ Development Using Typewriter

generic action method mvc with database call

I am searching for a way to make generic action methods that can be inherited by multiple controllers, so I don't have to repeat the same method in MVC for different controllers and tables. I think this would be applicable to a lot of the CRUD stuff I have to frequently do for multiple classes.
For example, here's the code I'd like to duplicate:
public ActionResult ToggleQC(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
BACTERIA_EVW bacteria = db.BACTERIA_EVW.Find(id);
if (bacteria == null)
{
return HttpNotFound();
}
//add/remove QC status (switch to whichever one it isn't right now)
if (bacteria.QCOn == null) //if it hasn't been QCed
{
bacteria.QCOn = DateTime.Now;
bacteria.QCBy = User.Identity.Name;
}
else //if it has been QCed and they are undoing it
{
bacteria.QCBy = null;
bacteria.QCOn = null;
}
//save changes
db.Entry(bacteria).State = EntityState.Modified;
db.SaveChanges();
//return updated QC status partial
return PartialView("_QCStatus", bacteria);
}
I need to do the same thing in a chemistry controller, but I'd rather not repeat the whole thing and just change one part. Is it possible to pass the model type into the method as a parameter, to replace BACTERIA_EVW? How would I do that?
I apologize if this is something really basic; I may not know the right terms to look for. I've searched for generic action methods but I haven't found any answers, although there was something about generic controllers - do I need to make a generic controller class somehow to include a method like this?
Thanks very much.
If you just care about removing code redundancy you can create a generic controller with that method and inherit other controllers from that:
namespace BaseControllers
{
public class CoolController
{
public virtual ViewResult Get()
{
var awesomeModel = new object();
return View(awesomeModel);
}
}
}
And in your child controller:
public class CoolController : BaseControllers.CoolController
{
public override ViewResult Get()
{
var ignoredResult = base.Get();
// ViewData.Model now refers to awesomeModel
return View("NotGet");
}
}
Same can happen for other CRUD operations.

Find a generic DbSet in a DbContext dynamically

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

Categories