API or business logic in angular - c#

We are porting code written in aspx web forms to angular frontend and business logics written in APIs. I am stuck with a use case where code-behind of aspx form make call to a class which has quite lean business logic.
I am not sure if I should make that class as a API/controller so the UI Element in angular can update it's content? I mean does it even make sense for this scenario to be qualified to be an API?
Code Behind of asp web form looks like this
var obj = ClassA.GetObject("name") //GetObject is a static method in the business layer
txt1.Text = obj.value;
Helper Class looks like the following
public class ClassA
{
public static MyClass GetObject(string name)
{
MyClass mo = new MyClass();
mo.useOtherName = true;
switch (name.ToUpper())
{
case "NAME":
mo.type = new Type();
break;
}
return mo;
}
}

Related

How to avoid writing many functions that just call another function when implementing a Business Logic layer

I am working on a web application that uses Angular 12 for the frontend and ASP.NET Core 6 for the backend. In our team we usually write just about anything as a 3-layer application (if possible) consisting of a presentation layer, a business logic layer and a data layer. In the case of this project, this would mean that when for example all entities of a certain type, let's call it Car, are requested from the server, the following would happen (simplified):
The request arrives in the CarController.cs controller. The carManager instance here belongs to the business layer and provides functions for interacting with car entities (CRUD for the most part). Dependency Injection is used to inject the carManager instance into the controller:
public async Task<ActionResult<List<Car>>> GetCars()
{
List<Car> cars = await this.carManager.GetCarsAsync();
return this.Ok(cars);
}
If there is anything business logic related, it will be done in the GetCarsAsync() function of the carManager. However, in many cases this is not necessary. Therefore, I often end up with "dumb" functions that just call the corresponding function of the data layer like this. The carAccessor in this example belongs to the data layer. Dependency Injection is also used here to inject its instance into the manager:
public async Task<ActionResult<List<Car>>> GetCarsAsync()
{
return this.carAccessor.GetCarsAsync();
}
The actual querying of the data is then done in the corresponding accessor for the entity. Example:
public async Task<List<Car>> GetCarsAsync()
{
List<Car> cars = new();
List<TblCar> dbCars = await this.Context.TblCars.ToListAsync();
foreach (TblCar dbCar in dbCars)
{
Car car = <AutoMapper instance>.Map<Car>(dbCar);
cars.Add(car);
}
return cars;
}
While this makes it easy to not mix up business logic and data access in the application, it really creates a whole lot of code that does nothing than just call other code. Therefore, in some cases the business layer is omitted simply because of laziness and business logic ends up just being implemented somewhere else, for example directly in the controller. Is there a simple solution for this?
Using generic base classes and inheritance could help you to reduce writing and maintaining of similar code everywhere for vanilla cases :
public abstract class BaseController<T, C>: Controller where T: class where C: IItemsManager<T>
{
protected C ItemManager { get; }
public virtual async Task<ActionResult<List<T>>> GetCars()
{
List<T> items = await this.ItemManager.GetItemsAsync();
return this.Ok(items);
}
}
public interface IItemsManager<T> where T : class
{
Task<List<T>> GetItemsAsync();
}
public class ItemsManager<T, B>: IItemsManager<T>
where T: class
where B: class
{
public virtual async Task<List<T>> GetItemsAsync()
{
List<T> items = new List<T>();
List<B> dbItems = await this.Context.Set<B>().ToListAsync();
foreach (B dbItem in dbItems)
{
T item = <AutoMapperinstance>.Map<T>(dbItem);
items.Add(item);
}
return items;
}
}
public class CarManager: ItemsManager<Car, TblCar>
{
}
public class CarController: BaseController<Car, CarManager>
{
}

How to move validation handling from a controller action to a decorator

Maintenance Edit
After using this approach for a while I found myself only adding the exact same boilerplate code in every controller so I decided to do some reflection magic. In the meantime I ditched using MVC for my views - Razor is just so tedious and ugly - so I basically use my handlers as a JSON backend. The approach I currently use is to decorate my queries/commands with a Route attribute that is located in some common assembly like this:
[Route("items/add", RouteMethod.Post)]
public class AddItemCommand { public Guid Id { get; set; } }
[Route("items", RouteMethod.Get)]
public class GetItemsQuery : IQuery<GetItemsResponse> { }
// The response inherits from a base type that handles
// validation messages and the like
public class GetItemsResponse : ServiceResponse { }
I then implemented an MVC host that extracts the annotated commands/queries and generates the controllers and handlers for me at startup time. With this my application logic is finally free of MVC cruft. The query responses are also automatically populated with validation messages. My MVC applications now all look like this:
+ MvcApp
+- Global.asax
+- Global.asax.cs - Startup the host and done
+- Web.config
After realizing I really don't use MVC outside the host - and constantly having issues with the bazillion dependencies the framework has - I implemented another host based on NServiceKit. Nothing had to be changed in my application logic and the dependencies are down to System.Web, NServiceKit and NServiceKit.Text that takes good care of the model binding. I know it's a very similar approach to how NServiceKit/ServiceStack does their stuff but I'm now totally decoupled from the web framework in use so in case a better one comes along I just implement another host and that's it.
The situation
I'm currently working on an ASP.NET MVC site that's implementing the businesslogic-view separation via the IQueryHandler and ICommandHandler abstractions (using the almighty SimpleInjector for dependency injection).
The Problem
I've got to attach some custom validation logic to a QueryHandler via a decorator and that's working pretty well in and of itself. The problem is that in the event of validation errors I want to be able to show the same view that the action would have returned but with information on the validation error of course. Here is a sample for my case:
public class HomeController : Controller
{
private readonly IQueryHandler<SomeQuery, SomeTransport> queryHandler;
public ActionResult Index()
{
try
{
var dto = this.queryHandler.Handle(new SomeQuery { /* ... */ });
// Doing something awesome with the data ...
return this.View(new HomeViewModel());
}
catch (ValidationException exception)
{
this.ModelState.AddModelErrors(exception);
return this.View(new HomeViewModel());
}
}
}
In this scenario I have some business logic that's handled by the queryHandler that is decorated with a ValidationQueryHandlerDecorator that throws ValidationExceptions when it is appropriate.
What I want it to do
What I want is something along the lines of:
public class HomeController : Controller
{
private readonly IQueryHandler<SomeQuery, SomeTransport> queryHandler;
public ActionResult Index()
{
var dto = this.queryHandler.Handle(new SomeQuery { /* ... */ });
// Doing something awesome with the data ...
// There is a catch-all in place for unexpected exceptions but
// for ValidationExceptions I want to do essentially the same
// view instantiation but with the model errors attached
return this.View(new HomeViewModel());
}
}
I've been thinking about a special ValidationErrorHandlerAttribute but then I'm losing the context and I can't really return the proper view. The same goes with the approach where I just wrap the IQueryHandler<,> with a decorator... I've seen some strange pieces of code that did some string sniffing on the route and then instantiating a new controller and viewmodel via Activator.CreateInstance - that doesn't seem like a good idea.
So I'm wondering whether there is a nice way to do this ... maybe I just don't see the wood from the trees. Thanks!
I don't think there's a way to make the action method oblivious to this, since the action method is in control of the returned view model, and in case of a validation exception you need to return a view model with all the actual data (to prevent the user from losing his changes). What you might be able to do however to make this more convenient is add an extension method for executing queries in an action:
public ActionResult Index()
{
var result = this.queryHandler.ValidatedHandle(this.ModelState, new SomeQuery { });
if (result.IsValid) {
return this.View(new HomeViewModel(result.Data));
}
else
{
return this.View(new HomeViewModel());
}
}
The ValidatedHandle extension method could look like this:
public static ValidatedResult<TResult> ValidatedHandle<TQuery, TResult>(
this IQueryHandler<TQuery, TResult> handler,
TQuery query, ModelStateDictionary modelState)
{
try
{
return new ValidatedResult<TResult>.CreateValid(handler.Handle(query));
}
catch (ValidationException ex)
{
modelState.AddModelErrors(ex);
return ValidatedResult<TResult>.Invalid;
}
}
Do note that you should only catch such validation exception if the validation is on data that the user has entered. If you send a query with parameters that are set programmatically, a validation exception simply means a programming error and you should blog up, log the exception and show a friendly error page to the user.

Using a DbContext variable from one Controller to Another

Hi I am using MVC 4 and C# to develop an application that has two controllers:
The first one is called Business, it has a method called Create that calls a method called CreatePartner from another Controller named PartnerController.
public class BusinessController : Controller
{
private storeContext db = new storeContext();
public ActionResult Create(Business business)
{
//Some stuff here
PartnerController pt = new PartnerController();
pt.CreatePartner(int partner_id);
//Here is another stuff that uses db DbContext variable
return RedirectToAction("Index");
}
}
This is the second controller Called Partner
public class PartnerController : Controller
{
private storeContext db = new storeContext();
public void CreatePartner(int partner_id)
{
//Some interesting stuff
}
}
Each controllers has its Dispose() method
The Problem is: After I called the CreatePartnet method from Business controller I try to use the db variable again to save other data but it throws me the following exception:
The operation can not be completed because the DbContext has been disposed
-What is the best way to Use methods from one controller to another that has the same DbContext variable name?.
-Something strange happens: My stuff works locally but when I publish my code in the IIS server is when the app throws that exception.
Thanks!
Might I suggest an alternative approach?
Controllers are not very good places for business logic; that is they're not very good places for "doing stuff". It's often demonstrated in MVC tutorials and examples in this manner but it's really only good for getting into MVC quickly - it's not very good practice.
Furthermore Controllers aren't really supposed to have methods to be called - from themselves or called from another Controller. Controllers should really just contain their Actions.
Instead, extract your logic to an external class. A Service is a design pattern in which commonly used business logic is abstracted away. That way things can have a reference to the service and execute the logic without knowing anything about the implementation.
Observe:
IPartnerService
public interface IPartnerService
{
void CreatePartner(int partnerId);
}
DefaultPartnerService
public class DefaultPartnerService : IPartnerService
{
private StoreContext db;
public DefaultPartnerService()
{
db = new StoreContext();
}
public void CreatePartner(int partnerId)
{
// Something interesting
}
}
BusinessController
public class BusinessController : Controller
{
private IPartnerService _partnerService;
public BusinessController()
{
_partnerService = new DefaultPartnerService();
}
public ActionResult Create(Business business)
{
_partnerService.CreatePartner(business.PartnerId);
return RedirectToAction("Index");
}
}
Of course this approach is also greatly simplified for educational purposes. It's not best practice yet, but it might put you on the right track. Eventually you'll discover problems with this approach and you'll gravitate to reading about Repositories, Unit of Work, Dependency Injection and so on.

Why are Controller methods like RedirectToAction() and HttpNotFound() protected internal?

I want to implement a service pattern to provide some logic for several of my ASP.NET MVC controllers. Depending on the result of the logic, I may want the controllers to redirect, or give a 404 not found, or various other responses. Therefore I want my controllers to be able to receive an out ActionResult parameter from the service method(s) that they can return to carry out these responses.
The trouble is that I don't see any way for the service to generate ActionResults. Because methods like RedirectToAction() and HttpNotFound() in the Controller class are set to protected internal, they cannot be accessed from the service class.
What is the rationale behind making them protected internal? How is my service supposed to indicate to the controllers what action result they should return?
An example of what I might want to do is allow the user, in several places, to set a configuration variable if they have permission. The controller code would look something like:
public ActionResult SetVariable(int variableId, int variableValue) {
ActionResult actionRes;
_svcVars.SetVariable(variableId, variableValue, out actionRes);
return actionRes;
}
... and the service code would look something like:
public bool SetVariable(int variableId, int variableValue, out ActionResult actionRes) {
ConfigRepository repoConfig = new ConfigRepository();
if (!repoConfig.VariableExists(variableId)) {
actionRes = HttpNotFound("Could not find config variable");
return false;
}
if (!repoConfig.VariableMayBeChanged(variableId)) {
actionRes = Redirect("/ChangeForbidden.html");
return false;
}
int variablesListId = repoConfig.SetVariable(variableId, variableValue);
actionRes = RedirectToAction("ViewVariablesList", new { listId = variablesListId });
return true;
}
The trouble is that I don't see any way for the service to generate ActionResults.
As with any object in .NET you could use its constructor in order to create an instance.
Just like that:
var values = new RouteValueDictionary(new
{
action = "ViewVariablesList",
listId = variablesListId
});
actionRes = new RedirectToRouteResult(values);
As far as why the corresponding methods on the Controller class are protected and internal, well, a question that you could address to the people designing the framework.

Microsoft Unity 2, how to register the following?

Right now we have a dll file that contains all the database calls and i can't change it. However i need to call i from my Mvc 3 project. The process to call it is simple, i use the following:
ManageProvider.GetProxy<T>(ident);
T is an interface that i want to get the class back from (its like an IoC of its own) and ident is the user identification class. So by calling
var classReturned = ManageProvider.GetProxy<ICommunity>(new UserIden{ Email = "test#test.com" });
I would get a class back with all the community functions.
Now i want to implement Unity in my Mvc 3 project. The question is, can i somehow add these calls to the dll file through unity?
I want to resolve the call by using:
var classReturned = myContainer.Resolve<ICommunity>(new UserIden{ Email = "test#test.com" });
How can i register this in Unity (or is it even possible) ?
Update:
1) Is it better to call the methods with the email/user ident instead of defining a Dependency property? (ex below)
2) There is a bout 20 or so interfaces in the dll file right now. Should i add them all to the same reposatory? (ex below)
public class ProxyWrapper : IDllRepository
{
[Dependency]
public UserIdent UserIdent { get; set; }
public ICommunity GetCommunity()
{
return ManageProvider.GetProxy<ICommunity>(UserIdent);
}
public IDesktop GetDesktop()
{
return ManageProvider.GetProxy<IDesktop>(UserIdent);
}
}
public interface IDllRepository
{
ICommunity GetCommunity();
IDesktop GetDesktop();
}
Whats the best way and how would i call it from my code?
Does the [Dependency] attribute also fall into the Service Locator anti pattern?
Update 23.05.11
1) Yes, something like that. They contain all the logic that is provided to all the projects that includes the dll file.
Regarding the ManagerProvider. It accepts an interface and returns the class that is mapped to this interface. So for the community, the interface looks like this (removed a lot of calls to keep it short, there is also posts, comments, community create/update etc):
List<CommunityThread> GetThreads(int pStartRowIndex, int pMaximumRows, string pOrderBy, string pSearchExpression);
Guid? CreateThread(string pTitle, string pDescription, string pPostContent);
bool DeleteThread(Guid pThreadId);
List<CommunityThread> GetCommunityUserThreads(Guid pCommunityUserId);
2) What i can't update is how the ManageProvider.GetProxy works. The GetProxy is a class in the dll file that is hardcoded. Here is the part for the community. The class does the same for all the other interfaces as well, if typeof(interface) ... return class.
private static IManageProxy GetProxyForInterface<T>(UserIdent pIdent)
{
....
if (typeof(T).Equals(typeof(ICommunity)))
return new PCommunity();
....
}
3) Once registered using this new wrapper class, i can call it through the following code (MvcUnityContainer is a static class that only has a property called Container):
var c = MvcUnityContainer.Container.Resolve<IBackendRepository>(new PropertyOverride("UserIdent",
new UserIdent()));
Global.asax
IUnityContainer container = InitContainer();
MvcUnityContainer.Container = container;
DependencyResolver.SetResolver(new UnityMvcResolver(container));
The question is, do i need the static class MvcUnityContainer? Is it possible to configure the DependecyResolver to do that for me? Something like (problem is that it doesn't accept the override parameter):
var c = DependencyResolver.Current.GetService<IBackendRepository>(new PropertyOverride("UserIdent", new UserIdent()));
I think you need to hide the creation behind another abstraction, for instance:
public interface ICommunityRepository
{
ICommunity GetByEmailAddress(string address);
}
public class ManageProviderCommunityRepository
: ICommunityRepository
{
public ICommunity GetByEmailAddress(string address)
{
var id = new UserIden { Email = address };
return ManageProvider.GetProxy<ICommunity>(id);
}
}
This will hide both the ManageProvider and the UserIden behind this abstraction, and allows you to replace it later on with something more useful and makes testing easier.
Registration now is very easy:
RegisterType<ICommunityRepository, ManageProviderCommunityRepository>();
Instead of calling myContainer.Resolve (as you do in your example), inject the dependencies in your classes. This prevents you from using the Service Locator anti-pattern.
Perhaps you could do something like this, using the InjectionFactory:
myContainer.RegisterType<ICommunity>(
new InjectionFactory(c => ManageProvider.GetProxy<ICommunity>(new UserIden {Email = "test#test.com"})));
var classReturned = myContainer.Resolve<ICommunity>();
... Though you wouldn't be able to pass the UserIden as a parameter to the Resolve call, so I'm not sure if this is what you want.
To register all the public classes of the assembly you could perhaps iterate over Assembly.GetTypes() and register them in the same way?

Categories

Resources