NgRx Data, EntityCollectionService's default Api not Match Asp.net Core Web Api - asp.net-web-api

I have service that extends EntityCollectionServiceBase of ngrx\data
#Injectable()
export class ProductService extends EntityCollectionServiceBase<Product> {
constructor(elementsFactory: EntityCollectionServiceElementsFactory) {
super('Product', elementsFactory);
}
and my asp.net controller is like this
[Route("api/[controller]")]
[ApiController]
public class ProductController : ApiController
{
// GET: api/<ProductController>
[HttpGet]
public async Task<ActionResult<ProductsListVm>> GetAll()
{
var vm = await Mediator.Send(new GetProductsListQuery());
return Ok(vm);
}
// GET api/<ProductController>/5
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
}
so when I call GetAll on entity service of ngrx\data it requests {url}/api/products/ while the asp.net web API controller only responds to {url}/api/product/
any configuration or trick to resolve with minimal code

You should define a plural name as follwoing:
import { EntityMetadataMap } from 'ngrx-data';
const entityMetadata: EntityMetadataMap = {
Product: {},
};
const pluralNames = { Product: 'product' };
export const entityConfig = {
entityMetadata,
pluralNames
};

Related

Conditional validation based on request route with asp.net core 2.2 and FluentValidation

So Basically i wrote a validator for my class with FluentValidation and also a filter to do the validation task for me in my webAPI project, so far it's OK but assume that my User class has firstname,lastname,email,password properties
and i have two routes (one for register and the other one for login)
and as you might have noticed required properties are different on these route.
Thus,should I really need to write individual validation for each and every action i have?because this makes a lot of code code duplication and it's hard to change.is there any way to just add required condition based on the request coming with single validation class?
Any suggestion???
A better practice would be to use a factory pattern for your validations and use a an action filter to short circuit bad requests. You could validate any action argument(Headers, Request Bodies, etc..) with something like this.
public class TestValidationAttribute : Attribute, IActionFilter
{
private string _requestModelName;
public TestValidationAttribute(string requestModelName)
{
_requestModelName = requestModelName;
}
public void OnActionExecuting(ActionExecutingContext context)
{
// using Microsoft.Extensions.DependencyInjection;
var services = context.HttpContext.RequestServices;
var accessor = services.GetService<IHttpContextAccessor>();
var factory = services.GetService<ITestValidatorFactory>();
var tokens = accessor.HttpContext.GetRouteData().DataTokens;
if (!tokens.TryGetValue("RouteName", out var routeNameObj))
{
throw new Exception($"Action doesn't have a named route.");
}
var routeName = routeNameObj.ToString();
var validator = factory.Create(routeName);
if (!context.ActionArguments.TryGetValue(_requestModelName, out var model))
{
throw new Exception($"Action doesn't have argument named {_requestModelName}.");
}
TestModel test;
try
{
test = (TestModel) model;
}
catch (InvalidCastException)
{
throw new Exception($"Action argument can't be casted to {nameof(TestModel)}.");
}
var validation = validator.Validate(test);
if (!validation.Successful)
{
context.Result = new BadRequestObjectResult(validation.ResponseModel);
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
}
public class TestController : Controller
{
[HttpPost]
[Route("Test/{id}", Name = "TestGet")]
[TestValidation("model")]
public IActionResult Test(TestModel model)
{
return Ok();
}
}
public class ValidationResult
{
public bool Successful { get; }
public ResponseModel ResponseModel { get; }
}
public class TestModel
{
}
public interface ITestValidator
{
ValidationResult Validate(TestModel model);
}
public interface ITestValidatorFactory
{
ITestValidator Create(string routeName);
}

How do I route to a method in ASP.NET Web API?

According to the documentation, if I have this in my WebApiConfig.cs:
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
I should be able to route to a method in my API controller using a URL like this:
http://localhost:55601/api/Customers/Search
Here is my method:
[ResponseType(typeof(int))]
[HttpPost]
public IHttpActionResult Search([FromBody]CustomerDTO SearchTerm)
{
string Name = SearchTerm.Name;
string Email = SearchTerm.Email;
string PhoneNumber = SearchTerm.Phone;
var customer = db.Customers.Single(c => c.Name == Name && c.EmailAddress == Email && c.PhoneNumber == PhoneNumber);
return Ok(customer.id);
}
I'm sending the search data as a JSON object (using HTTP POST method) in the request body.
However, I get an error saying:
Multiple actions were found that match the request
I only have one method in this controller called Search.
I would have thought this should be pretty straightforward, and work the same way it does with MVC controllers. But I think I'm missing something obvious. Can anyone tell me what it is?
EDIT: As per #KevinLaw's request, adding code for controller showing upblic methods. Also, for further information the following request (HTTP GET) works as expected:
http://localhost:55601/api/Customers?email=[recipient#domain]
public class CustomersController : ApiController
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: api/Customers
public IQueryable<Customer> GetCustomers()
{
//...
}
// GET: api/Customers/5
[ResponseType(typeof(Customer))]
public IHttpActionResult GetCustomer(int id)
{
//...
}
// GET: api/Customers/5
[ResponseType(typeof(Customer))]
public IHttpActionResult GetCustomerByEmail(string email)
{
//...
}
// PUT: api/Customers/5
[ResponseType(typeof(void))]
public IHttpActionResult PutCustomer(int id, Customer customer)
{
//...
}
// POST: api/Customers
[ResponseType(typeof(Customer))]
public IHttpActionResult PostCustomer(Customer customer)
{
//...
}
[ResponseType(typeof(int))]
[HttpPost]
public IHttpActionResult SearchCustomer([FromBody]CustomerDTO SearchTerm)
{
//...
}
// DELETE: api/Customers/5
[ResponseType(typeof(Customer))]
public IHttpActionResult DeleteCustomer(int id)
{
//...
}
}
The problem here is that the WebApiController uses the REST API specs.
Which state that in a Web Api Controller there can be Zero - One Http Verb.
What i mean by that is that you can have one GET,PUT,POST,DELETE,PATCH
The reason you don't have any problem with the GET is because you have them correctly overloaded. () (int) (string).
But your Posts is (Customer) (CustomerDTO) They are both complex objects and the Binder cannot identify which is which when binding to the complex object.
For this to work you need to use Route Attributes or explicit route.
Attribute Routing
Explicit Routing pt1
Explicit Routing pt2
I think the links are enough to get you started.
If you still want to see some code on your specific case leave a comment below and i will give you some examples.
Thanks
EDIT: Added Examples
Attribute Routing
On WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
}
On Controller
[RoutePrefix("api/test")]
public class TestingController : ApiController
{
[HttpGet]
[Route("")]
public IEnumerable<string> Get()
{
return new[] { "value1", "value2" };
}
[HttpPost]
[Route("search")]
public IHttpActionResult Post([FromBody]SearchCriteria criteria)
{
return Ok(criteria);
}
}
public class SearchCriteria
{
public string Name { get; set; }
}
Explicit Routing
On WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes config.Routes.MapHttpRoute(
name: "SearchTest",
routeTemplate: "api/test/search",
defaults: new { controller = "Testing", action = "Search" }
);
config.Routes.MapHttpRoute(
name: "TestingController",
routeTemplate: "api/test/{id}",
defaults: new { controller = "Testing", id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
On Controller
public class TestingController : ApiController
{
[HttpGet]
public IEnumerable<string> Get()
{
return new[] { "value1", "value2" };
}
[HttpPost]
public IHttpActionResult Search([FromBody]SearchCriteria criteria)
{
return Ok(criteria);
}
}
public class SearchCriteria
{
public string Name { get; set; }
}

Put, Delete... Method not allowed in Orchard

I've created WebApi controller based on following tutorial: sebastienros website
My modules name is Company.Accounts.
public class AccountController : ApiController
{
[HttpPost]
public string LogIn([FromBody] UserModel user)
{
// this is working
return this.accountService.LogIn(user.UserName, user.Password);
}
[HttpPut]
public string SomePuthMethod([FromBody] UserModel user)
{
// method not allowed
// some code...
}
}
Implementation of IHttpRouteProvider looks like:
private IEnumerable<RouteDescriptor> GetAccountRoute()
{
yield return new HttpRouteDescriptor
{
Name = "Account",
Priority = 10,
RouteTemplate = "Api/Account",
Defaults = new
{
area = "Company.Accounts",
controller = "Account"
}
};
}
Unfortunately, everything except GET and POST *is not working*. I'm getting simple
Method not allowed.
What's wrong? My Orchard version is 1.7.1.
You put them in the MethodNames public HttpResponseMessage Post([FromBody]...){}

Property injection in to Web Api controller using Autofac

I'm trying to set a property on an System.Web.Http.ApiController to a value of a resolved IServerPackageRepository. The controller runs in a HttpSelfHostServer and the DependencyResolver has been set to AutofacWebApiDependencyResolver. Here is the code from the Autofac.Module.Load method
...
builder.RegisterType<ServerPackageRepository>()
.As<IServerPackageRepository>()
.SingleInstance()
.WithParameter("path", this.StoragePath);
builder.RegisterApiControllers(Assembly.GetExecutingAssembly())
.PropertiesAutowired();
The ApiController controller itself has a property of type
public IServerPackageRepository Repository { get; set; }
but is never resolved.
I am trying to do it this way because ApiController won't take nothing but default constructors. Any suggestions on how to do this the correct way using Autofac?
If the ApiController is only using the default constructor is sounds like the dependency resolver is not being called and may not be registered with Web API correctly. Here is a working example of self-hosting with constructor injection.
The dependency (in this case a simple logger):
public interface ILogger
{
void Log(string text);
}
public class Logger : ILogger
{
public void Log(string text)
{
Debug.WriteLine(text);
}
}
A simple controller with a dependency on the logger:
public class ValuesController : ApiController
{
readonly ILogger _logger;
public ValuesController(ILogger logger)
{
_logger = logger;
}
// GET api/values
public IEnumerable<string> Get()
{
_logger.Log("GET api/values");
return new string[] { "value1", "value2" };
}
}
The console application:
class Program
{
static void Main(string[] args)
{
var configuration = new HttpSelfHostConfiguration("http://localhost:8080");
configuration.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var builder = new ContainerBuilder();
// Register API controllers using assembly scanning.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// Register API controller dependencies.
builder.Register<ILogger>(c => new Logger()).SingleInstance();
var container = builder.Build();
// Set the dependency resolver implementation.
var resolver = new AutofacWebApiDependencyResolver(container);
configuration.DependencyResolver = resolver;
// Open the HTTP server and listen for requests.
using (var server = new HttpSelfHostServer(configuration))
{
server.OpenAsync().Wait();
Console.WriteLine("Hosting at http://localhost:8080/{controller}");
Console.ReadLine();
}
}
}
Hit the controller action using:
http://localhost:8080/api/values
Please test this out and let me know if you have any problems.
Not sure if this is what you want but you can create your own base controller and inject the IServerPackageRepository into it.
public class MyApiController : ApiController {
public IServerPackageRepository ServerPackageRepository { get; set; }
public MyApiController(IServerPackageRepository serverPackageRepository) {
ServerPackageRepository = serverPackageRepository;
}
}
Then, use this as your base controller:
public class ProductsController : MyApiController {
public ProductsController(IServerPackageRepository serverPackageRepository)
: base(serverPackageRepository) {
}
public IEnumerable<Product> Get() {
ServerPackageRepository.DoWork();
//...
}
}
An alternative would be to directly wire your dependency to the property like so:
var repo = new ServerPackageRepository(path: this.StoragePath);
builder.RegisterInstance(repo)
.SingleInstance();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly())
.WithProperty("Repository", repo)
.PropertiesAutowired();

MVC3 Generic CRUD Controllers, Services and Repositories

We are attempting to create a generic CRUD controller in our MVC3 application which can handle the following actions Edit (Create/Edit), Delete and List (I have already looked here). The project has the Web (MVC) layer, Service (BLL) layer and a Repository (DB) layer. We are using constructor dependency injection as follows:
SERVICE LAYER
public class MyService : IMyService
{
private IMyRepository _myRepository;
public MySerivce(IMyRepository myRepository)
{
this._myRepository = myRepository;
}
public IEnumerable<IMyObject> GetObjects(int intParentKey)
{
return (IMyObject)_myRepository.GetObjects(intParentKey).Select(o => new MyObject(o));;
}
}
CONTROLLER
public class MyController
{
private IMyService _myService;
public MyController(IMyService myService)
{
this._myService = myService;
}
public ActionResult Index()
{
return View("Index", new List<MyFormModel>(_myService.GetObjects(intKeyValue).Select(a => new MyFormModel(a))));
}
}
The goal is to have a generic CRUD controller, but the difficulty is that the controllers will need to have knowledge of the MyFormModel object as well as a specific service. We would also like to have a generic service which handles the GetObjects, SaveObject, DeleteObject functions, but then that would need knowledge of the IMyObject interface, the MyObject implementation of IMyObject and the IMyRepository type. It appears right now that doing all of this with dependency injection is somewhat complicated.
FYI, the Service layer needs to change on the fly within the WEB portion of the tool depending on the current configuration.
In response to the generic CRUD comment, here is a BASE controller which accepts a BASE service through dependency injection:
public abstract class BaseCRUDController<T>
where T : class
{
private IBaseService _baseService;
public BaseCRUDController(IBaseService baseService)
{
this._baseService = baseService;
}
public ActionResult Index()
{
Type classType = typeof(T);
ConstructorInfo ciClass = classType.GetConstructor(new Type[] {});
return View("Index", new List<T>(_baseService.GetObjects(intKey).Select(o => (T)ciClass.Invoke(new object[] { o }))));
}
}
Obviously this generic controller is fairly straightforward, but the difficulty comes from the service side where the IMyObject and MyObject objects reside. The definition of the generic BaseService will require you to include the types of all of the objects in the base controller which is what we are trying to avoid. The code below could be way off the mark which is why I am asking for help:
SERVICE CLASS
public class MySerivce : BaseService<IMyObject, MyObject, DBObject>
{
public MySerivce(IMyRepository myRepository) :
base(myRepository)
{
}
}
BASE SERVICE INTERFACE
public interface IBaseService<IMT, MT, DT>
where IMT : class
where MT : class
where DT : class
{
IEnumerable<ValidationResult> Save(IMT model);
void Delete(int intKey);
IMT Get(int? intKey);
IEnumerable<IMT> GetObjects(int intParentKey);
}
BASE SERVICE IMPLEMENTATION
public class BaseService<IMT, MT, DT> : IBaseService<IMT, MT, DT>
where IMT : class
where MT : class
where DT : class
{
private IBaseRepository _baseRepository;
public BaseService(IBaseRepository baseRepository)
{
this._baseRepository = baseRepository;
}
public IEnumerable<ValidationResult> Save(IMT model)
{
List<ValidationResult> lResults = new List<ValidationResult>();
if (Validator.TryValidateObject(model, new ValidationContext(model, serviceProvider: null, items: null), lResults))
{
Type tDT = typeof(DT);
ConstructorInfo ciDTClass = tDT.GetConstructor(new Type[] { });
DT dtObject = (DT)ciDTClass.Invoke(new object[] { });
Mapper.CreateMap<IMT, DT>();
Mapper.Map(model, dtObject);
_baseRepository.Save<DT>(dtObject);
}
return lResults;
}
public void Delete(int intKey)
{
_baseRepository.Delete<DT>(intKey);
}
public IMT Get(int? intKey)
{
Type tMT = typeof(MT);
ConstructorInfo ciMTClass = tMT.GetConstructor(new Type[] { });
DT dtObject = _baseRepository.Get<DT>(intKey);
if (dtObject == null)
{
Type tDT = typeof(DT);
ConstructorInfo ciDTClass = tDT.GetConstructor(new Type[] { });
dtObject = (DT)ciDTClass.Invoke(new object[] { });
}
return (IMT)ciMTClass.Invoke(new object[] { dtObject });
}
public IEnumerable<IMT> GetObjects(int intParentKey)
{
Type tMT = typeof(MT);
ConstructorInfo ciMTClass = tMT.GetConstructor(new Type[] { });
IEnumerable<DT> dbObjects = _baseRepository.GetObjects<DT>(intParentKey);
return (IEnumerable<IMT>)dbObjects.Select(o => (MT)ciMTClass.Invoke(new object[] { o })); ;
}
}

Resources