Call two Action Methods and Combine the responses to produce new response in .NET Web API - asp.net-web-api

I have two versions of an API.
The second version of API will be having only one action method instead of two action methods in first version of API.
Second version of API action method will basically combine responses of first version of API's both action methods and return combined response to client.
Example code as follows:
[ApiController]
[Route("[controller]")]
public class NumbersV1Controller : ControllerBase
{
private readonly ILogger<NumbersV1Controller> _logger;
public NumbersV1Controller(ILogger<NumbersV1Controller> logger)
{
_logger = logger;
}
[HttpGet]
public int Get()
{
return 1;
}
[HttpPost]
public int Post()
{
return 2;
}
}
[ApiController]
[Route("[controller]")]
public class NumbersV2Controller : ControllerBase
{
private readonly ILogger<NumbersV2Controller> _logger;
public NumbersV2Controller(ILogger<NumbersV2Controller> logger)
{
_logger = logger;
}
[HttpPost]
public IEnumerable<int> Get()
{
// Method 1: Make a direct HTTP request.
// int response1 = HTTPClientHelper.GetRequest("Get", "NumbersV1");
// int response2 = HTTPClientHelper.PostRequest("Post", "NumbersV1");
// Method 2: Use instances and set controller context.
NumbersV1Controller numbersV1Controller = new NumbersV1Controller(null);
numbersV1Controller.ControllerContext = this.ControllerContext;
int response1 = numbersV1Controller.Get();
int response2 = numbersV1Controller.Post();
// Method 3: Use RedirectToAction method.
// RedirectToActionResult response1 = RedirectToAction("Get", "NumbersV1");
// RedirectToActionResult response2 = RedirectToAction("Post", "NumbersV1");
return new List<int>() { response1, response2 };
}
}
Method 1: Make a direct HTTP request.
It works perfectly but it is having additional boilerplate code and also it like making a new network call.
Method 2: Use instances and set controller context.
Not sure if this will work perfectly like can I access the Request object in version 1 controller and not sure how to initialize the version 2 controller will multiple injected objects
Method 3: Use RedirectToAction method.
I was assuming RedirectToAction will work but I don't see the result of the Action method in response object RedirectToActionResult.
What are the best options available for doing this in .NET Web API or is there any other way of doing this elegently?

Avoid using method 2 / method 3. Why? It violates so many patterns and performance will be an issue.
Method 1 is average if you really want to do it that way but will cost a network call though.
Method 4:
You can call directly inline business logic code from your V2 controller. If you already separated your business logic code to an individual service then you need to call it from your controller.
I have introduced a new class to do all the logical operations. You might have a similar one / many service classes for handling business requirements.
Let me give you an example:
public class Number1Controller : BaseController {
// You can use DI container to resolve this. I am using this as an example.
private readonly Service _service = new();
[HttpGet("{id}")]
public int GetById(int id) => _service.GetById(id);
[HttpGet("{name}")]
public string GetByName(string name) => _service.GetByName(name);
}
public class Number2Controller : BaseController {
// You can use DI container to resolve this. I am using this as an example.
private readonly Service _service = new();
[HttpGet("{id}")]
public int GetById(int id) => _service.GetById(id);
[HttpGet("{name}")]
public string GetByName(string name) => _service.GetByName(name);
}
// Business Logic Service
public class Service {
public int GetById(int id) => 1;
public string GetByName(string name) => "Stack Over Flow";
}

Related

initialize objects in ASP.custom middleware and inject them

I have an ASP.NET Core Web API which reads an auth token in the request header and decodes the values in it.
I have written custom middleware to decode the token. I have also created a UserContext object to hold the values decoded from the token and I'm setting the decoded values into the UserContext object.
I now want to be able to inject the UserContext object (which was created inside the custom middleware) into my contollers, and I'm unable to figure out how to do that.
Please help.
You can use the HttpContext.Items
In your middleware you will have access to the HttpContext, ofcourse
You can store your user context in the items dictionary which is transient and scoped to the lifetime of one http request. Below is an example middleware where 'context' is the Http context object. You will have this object in your middleware.
app.Use(async (context, next) =>
{
context.Items.Add("UserContext", new UserContext());
await next.Invoke();
});
You can then access the HttpContext in your controller by injecting the IHttpContextAccessor object.
public class ApiController : Controller
{
public readonly IHttpContextAccessor _context;
public ApiController(IHttpContextAccessor context)
{
_context = context;
}
public IActionResult Get()
{
// Get the http context
UserContext userContext = (UserContext) _context.HttpContext.Items["UserContext"];
return Ok();
}
}
From the IHttpContextAccessor, you can get the HttpContext object, and from that you can get the Items dictionary.
Of course, do some checking to see if the key "UserContext" exists but I think this will work for you
EDIT
Because you will want to pass it to other repository/services.
Instead of passing the HttpContextAccessor to all of them, which you can do. Create a service the encapsulates the creation of the UserContext object.
It can look something like this.
public interface IRepositry { }
public class Repositry : IRepositry
{
private IUserContextService _userContextService;
public Repositry(IUserContextService userContextService)
{
_userContextService = userContextService;
}
}
public class UserContext
{
}
public interface IUserContextService
{
UserContext GetUser();
}
public class UserContextService : IUserContextService
{
private readonly IHttpContextAccessor _context;
public UserContextService(IHttpContextAccessor context)
{
_context = context;
}
public UserContext GetUser()
{
var token = _context.HttpContext.Request.Headers["UserToken"];
// do something with the token to create the UserContext;
return new UserContext();
}
}
Create a UserContextService that reads from the HttpContext. Make the UserContextService a singleton but when you get the user, always return a new UserContext, this is because you of course in a multi-threaded environment and you never want to persist this object because you may end up reading someone else's UserContext, so always return new. Register this service in your ConfigureServices method in your startup class .
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IUserContextService, UserContextService>();
services.AddSingleton<IRepositry, Repositry>(serviceCollection => new Repositry(serviceCollection.GetService<IUserContextService>()));
}
You can then inject your repository to your API controller for example
public class ApiController : Controller
{
public readonly IRepositry _repositry;
public ApiController(IRepositrycontext repositry)
{
_repositry= repositry;
}
public IActionResult Get()
{
// Get the http context
return Ok();
}
}

Pass an object from ActionFilter.OnActionExecuting() to an ApiController

I wish to create an object per http request within an ActionFilter and pass this object to the controller. So far I have tried Request.Properties[] like the following
public class DbReadonlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
actionContext.Request.Properties["CustomObjectKey"] = new MyClass();
And I have also tried to assign the new object direct to a ControllerBase class.
public class DbReadonlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var controller = (MyControllerBase) actionContext.ControllerContext.Controller;
controller.StorageContextFactory = new MyClass();
The problem is that neither technique delivers an instance of MyClass to the controller because the new Property["CustomObjectKey"] is lost in the Webapi pipeline by the time a controller method is invoked.
The controller is re-instantiated by the webapi pipeline after the call to action filter OnActionExecuting().
Break points confirm the Webapi pipeline schedules the following event flow during a single http request.
constructor MyControllerBase()
MyAuthenticationFilter
Filter OnActionExecuting()
constructor MyControllerBase()
MyController.MethodA()
The double instantiation of MyControler is odd, but right now I am looking for any technique to pass a newly created object from an action filter to a controller.
Edit-1: The MyAuthorizationFilter mentioned in v1 of this question is actually an Authentication filter. Still investigating.
Solution: The bug was in another filter. After I removed my authentication filter the problem reported in this question went away.
You will have to use .add method Request.Properties collection.
public class DbReadonlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
actionContext.Request.Properties.Add(new KeyValuePair<string, object>("CustomObjectKey", new MyClass()));
You can retrieve this value from your api controller.
object _customObject= null;
if (Request.Properties.TryGetValue("CustomObjectKey", out _customObjectKey))
{
MyClass myObject = (MyClass)_customObject;
}
Another way to pass variable from ActionFilter.OnActionExecuting() to an ApiController:
public class CustomFilterAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
actionContext.ControllerContext.RequestContext.RouteData.Values["CustomValue"] = "CustomValue";
}
}
Pay attention to use ActionFilterAttribute for Web API :
System.Web.Http.Filters.ActionFilterAttribute
Not for MVC classic :
System.Web.Mvc.ActionFilterAttribute
Using:
[CustomFilter]
public class SomeController : ApiController
{
string customValue = RequestContext.RouteData.Values.ToDictionary(x => x.Key, y => y.Value)["user_id"].ToString();
//...
}

How to correctly use PagedResourcesAssembler from Spring Data?

I'm using Spring 4.0.0.RELEASE, Spring Data Commons 1.7.0.M1, Spring Hateoas 0.8.0.RELEASE
My resource is a simple POJO:
public class UserResource extends ResourceSupport { ... }
My resource assembler converts User objects to UserResource objects:
#Component
public class UserResourceAssembler extends ResourceAssemblerSupport<User, UserResource> {
public UserResourceAssembler() {
super(UserController.class, UserResource.class);
}
#Override
public UserResource toResource(User entity) {
// map User to UserResource
}
}
Inside my UserController I want to retrieve Page<User> from my service and then convert it to PagedResources<UserResource> using PagedResourcesAssembler, like displayed here: https://stackoverflow.com/a/16794740/1321564
#RequestMapping(value="", method=RequestMethod.GET)
PagedResources<UserResource> get(#PageableDefault Pageable p, PagedResourcesAssembler assembler) {
Page<User> u = service.get(p)
return assembler.toResource(u);
}
This doesn't call UserResourceAssembler and simply the contents of User are returned instead of my custom UserResource.
Returning a single resource works:
#Autowired
UserResourceAssembler assembler;
#RequestMapping(value="{id}", method=RequestMethod.GET)
UserResource getById(#PathVariable ObjectId id) throws NotFoundException {
return assembler.toResource(service.getById(id));
}
The PagedResourcesAssembler wants some generic argument, but then I can't use T toResource(T), because I don't want to convert my Page<User> to PagedResources<User>, especially because User is a POJO and no Resource.
So the question is: How does it work?
EDIT:
My WebMvcConfigurationSupport:
#Configuration
#ComponentScan
#EnableHypermediaSupport
public class WebMvcConfig extends WebMvcConfigurationSupport {
#Override
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(pageableResolver());
argumentResolvers.add(sortResolver());
argumentResolvers.add(pagedResourcesAssemblerArgumentResolver());
}
#Bean
public HateoasPageableHandlerMethodArgumentResolver pageableResolver() {
return new HateoasPageableHandlerMethodArgumentResolver(sortResolver());
}
#Bean
public HateoasSortHandlerMethodArgumentResolver sortResolver() {
return new HateoasSortHandlerMethodArgumentResolver();
}
#Bean
public PagedResourcesAssembler<?> pagedResourcesAssembler() {
return new PagedResourcesAssembler<Object>(pageableResolver(), null);
}
#Bean
public PagedResourcesAssemblerArgumentResolver pagedResourcesAssemblerArgumentResolver() {
return new PagedResourcesAssemblerArgumentResolver(pageableResolver(), null);
}
/* ... */
}
SOLUTION:
#Autowired
UserResourceAssembler assembler;
#RequestMapping(value="", method=RequestMethod.GET)
PagedResources<UserResource> get(#PageableDefault Pageable p, PagedResourcesAssembler pagedAssembler) {
Page<User> u = service.get(p)
return pagedAssembler.toResource(u, assembler);
}
You seem to have already found out about the proper way to use but I'd like to go into some of the details here a bit for others to find as well. I went into similar detail about PagedResourceAssembler in this answer.
Representation models
Spring HATEOAS ships with a variety of base classes for representation models that make it easy to create representations equipped with links. There are three types of classes provided out of the box:
Resource - an item resource. Effectively to wrap around some DTO or entity that captures a single item and enriches it with links.
Resources - a collection resource, that can be a collection of somethings but usually are a collection of Resource instances.
PagedResources - an extension of Resources that captures additional pagination information like the number of total pages etc.
All of these classes derive from ResourceSupport, which is a basic container for Link instances.
Resource assemblers
A ResourceAssembler is now the mitigating component to convert your domain objects or DTOs into such resource instances. The important part here is, that it turns one source object into one target object.
So the PagedResourcesAssembler will take a Spring Data Page instance and transform it into a PagedResources instance by evaluating the Page and creating the necessary PageMetadata as well as the prev and next links to navigate the pages. By default - and this is probably the interesting part here - it will use a plain SimplePagedResourceAssembler (an inner class of PRA) to transform the individual elements of the page into nested Resource instances.
To allow to customize this, PRA has additional toResource(…) methods that take a delegate ResourceAssembler to process the individual items. So you end up with something like this:
class UserResource extends ResourceSupport { … }
class UserResourceAssembler extends ResourceAssemblerSupport<User, UserResource> { … }
And the client code now looking something like this:
PagedResourcesAssembler<User> parAssembler = … // obtain via DI
UserResourceAssembler userResourceAssembler = … // obtain via DI
Page<User> users = userRepository.findAll(new PageRequest(0, 10));
// Tell PAR to use the user assembler for individual items.
PagedResources<UserResource> pagedUserResource = parAssembler.toResource(
users, userResourceAssembler);
Outlook
As of the upcoming Spring Data Commons 1.7 RC1 (and Spring HATEOAS 0.9 transitively) the prev and next links will be generated as RFC6540 compliant URI templates to expose the pagination request parameters configured in the HandlerMethodArgumentResolvers for Pageable and Sort.
The configuration you've shown above can be simplified by annotating the config class with #EnableSpringDataWebSupport which would let you get rid off all the explicit bean declarations.
I wanted to convert list of Resources to page. but when giving it PagedResourcesAssembler it was eating up the internal links.
This will get your List paged.
public class JobExecutionInfoResource extends ResourceSupport {
private final JobExecutionInfo jobExecution;
public JobExecutionInfoResource(final JobExecutionInfo jobExecution) {
this.jobExecution = jobExecution;
add(ControllerLinkBuilder.linkTo(methodOn(JobsMonitorController.class).get(jobExecution.getId())).withSelfRel()); // add your own links.
}
public JobExecutionInfo getJobExecution() {
return jobExecution;
}
}
Paged resource Providing ResourceAssembler telling Paged resource to use it, which does nothing simply return's it back as it is already a resource list that is passed.
private final PagedResourcesAssembler<JobExecutionInfoResource> jobExecutionInfoResourcePagedResourcesAssembler;
public static final PageRequest DEFAULT_PAGE_REQUEST = new PageRequest(0, 20);
public static final ResourceAssembler<JobExecutionInfoResource, JobExecutionInfoResource> SIMPLE_ASSEMBLER = entity -> entity;
#GetMapping("/{clientCode}/{propertyCode}/summary")
public PagedResources<JobExecutionInfoResource> getJobsSummary(#PathVariable String clientCode, #PathVariable String propertyCode,
#RequestParam(required = false) String exitStatus,
#RequestParam(required = false) String jobName,
Pageable pageRequest) {
List<JobExecutionInfoResource> listOfResources = // your code to generate the list of resource;
int totalCount = 10// some code to get total count;
Link selfLink = linkTo(methodOn(JobsMonitorController.class).getJobsSummary(clientCode, propertyCode, exitStatus, jobName, DEFAULT_PAGE_REQUEST)).withSelfRel();
Page<JobExecutionInfoResource> page = new PageImpl<>(jobExecutions, pageRequest, totalCount);
return jobExecutionInfoResourcePagedResourcesAssembler.toResource(page, SIMPLE_ASSEMBLER, selfLink);
}
ALTERNATIVE WAY
Another way is use the Range HTTP header (read more in RFC 7233). You can define HTTP header this way:
Range: resources=20-41
That means, you want to get resource from 20 to 41 (including). This way allows consuments of API receive exactly defined resources.
It is just alternative way. Range is often used with another units (like bytes etc.)
RECOMMENDED WAY
If you wanna work with pagination and have really applicable API (hypermedia / HATEOAS included) then I recommend add Page and PageSize to your URL. Example:
http://host.loc/articles?Page=1&PageSize=20
Then, you can read this data in your BaseApiController and create some QueryFilter object in all your requests:
{
var requestHelper = new RequestHelper(Request);
int page = requestHelper.GetValueFromQueryString<int>("page");
int pageSize = requestHelper.GetValueFromQueryString<int>("pagesize");
var filter = new QueryFilter
{
Page = page != 0 ? page : DefaultPageNumber,
PageSize = pageSize != 0 ? pageSize : DefaultPageSize
};
return filter;
}
Your api should returns some special collection with information about number of items.
public class ApiCollection<T>
{
public ApiCollection()
{
Data = new List<T>();
}
public ApiCollection(int? totalItems, int? totalPages)
{
Data = new List<T>();
TotalItems = totalItems;
TotalPages = totalPages;
}
public IEnumerable<T> Data { get; set; }
public int? TotalItems { get; set; }
public int? TotalPages { get; set; }
}
Your model classes can inherit some class with pagination support:
public abstract class ApiEntity
{
public List<ApiLink> Links { get; set; }
}
public class ApiLink
{
public ApiLink(string rel, string href)
{
Rel = rel;
Href = href;
}
public string Href { get; set; }
public string Rel { get; set; }
}

webapi actionfilters, how to inject a value when using different argument types that inherit from a base type

I have a base request type..
class RequestBase
{
public string inputId;
public string derivedid;
}
and types that inherit ..
class RequestA : RequestBase
{
public string name;
}
and
class RequestB : RequestBase
{
public string color;
}
I have a webapi service, some actions take an input parameter of RequestA, some take RequestB
[HttpPost]
[MyFilter]
[ActionName("Process1")]
public HttpResponseMessage Process1(RequestA request)
{
//do something with request.derivedId
}
[HttpPost]
[MyFilter]
[ActionName("Process2")]
public HttpResponseMessage Process2(RequestB request)
{
//do something with request.derivedId
}
I have an actionfilter that takes the inputId from the request and generates a derivedId
public override void OnActionExecuting(HttpActionContext actionContext)
{
RequestBase request = (RequestBase)actionContext.ActionArguments["request"];
string inputId = request.inputId;
string derivedId = inputId + "123";
// ?? somehow inject derivedId back into the actionContext so that my controller methods can access?
}
As my comment states above, I'd like to populate the derivedId field and have it accessible to my controller methods.
Thanks in advance
There's a few solutions to this problem already described in this thread - one of them should suit you:
ASP.NET MVC Pass object from Custom Action Filter to Action

Issues with my MVC repository pattern and StructureMap

I have a repository pattern i created on top of the ado.net entity framework. When i tried to implement StructureMap to decouple my objects, i kept getting StackOverflowException (infinite loop?). Here is what the pattern looks like:
IEntityRepository where TEntity : class
Defines basic CRUD members
MyEntityRepository : IEntityRepository
Implements CRUD members
IEntityService where TEntity : class
Defines CRUD members which return common types for each member.
MyEntityService : IEntityService
Uses the repository to retrieve data and return a common type as a result (IList, bool and etc)
The problem appears to be with my Service layer. More specifically with the constructors.
public PostService(IValidationDictionary validationDictionary)
: this(validationDictionary, new PostRepository())
{ }
public PostService(IValidationDictionary validationDictionary, IEntityRepository<Post> repository)
{
_validationDictionary = validationDictionary;
_repository = repository;
}
From the controller, i pass an object that implements IValidationDictionary. And i am explicitly calling the second constructor to initialize the repository.
This is what the controller constructors look like (the first one creates an instance of the validation object):
public PostController()
{
_service = new PostService(new ModelStateWrapper(this.ModelState));
}
public PostController(IEntityService<Post> service)
{
_service = service;
}
Everything works if i don't pass my IValidationDictionary object reference, in which case the first controller constructor would be removed and the service object would only have one constructor which accepts the repository interface as the parameter.
I appreciate any help with this :) Thanks.
It looks like the circular reference had to do with the fact that the service layer was dependent on the Controller's ModelState and the Controller dependent on the Service layer.
I had to rewrite my validation layer to get this to work. Here is what i did.
Define generic validator interface like below:
public interface IValidator<TEntity>
{
ValidationState Validate(TEntity entity);
}
We want to be able to return an instance of ValidationState which, obviously, defines the state of validation.
public class ValidationState
{
private readonly ValidationErrorCollection _errors;
public ValidationErrorCollection Errors
{
get
{
return _errors;
}
}
public bool IsValid
{
get
{
return Errors.Count == 0;
}
}
public ValidationState()
{
_errors = new ValidationErrorCollection();
}
}
Notice that we have an strongly typed error collection which we need to define as well. The collection is going to consist of ValidationError objects containing the property name of the entity we're validating and the error message associated with it. This just follows the standard ModelState interface.
public class ValidationErrorCollection : Collection<ValidationError>
{
public void Add(string property, string message)
{
Add(new ValidationError(property, message));
}
}
And here is what the ValidationError looks like:
public class ValidationError
{
private string _property;
private string _message;
public string Property
{
get
{
return _property;
}
private set
{
_property = value;
}
}
public string Message
{
get
{
return _message;
}
private set
{
_message = value;
}
}
public ValidationError(string property, string message)
{
Property = property;
Message = message;
}
}
The rest of this is StructureMap magic. We need to create validation service layer which will locate validation objects and validate our entity. I'd like to define an interface for this, since i want anyone using validation service to be completely unaware of the StructureMap presence. Besides, i think sprinkling ObjectFactory.GetInstance() anywhere besides the bootstrapper logic a bad idea. Keeping it centralized is a good way to insure good maintainability. Anyway, i use the decorator pattern here:
public interface IValidationService
{
ValidationState Validate<TEntity>(TEntity entity);
}
And we finally implement it:
public class ValidationService : IValidationService
{
#region IValidationService Members
public IValidator<TEntity> GetValidatorFor<TEntity>(TEntity entity)
{
return ObjectFactory.GetInstance<IValidator<TEntity>>();
}
public ValidationState Validate<TEntity>(TEntity entity)
{
IValidator<TEntity> validator = GetValidatorFor(entity);
if (validator == null)
{
throw new Exception("Cannot locate validator");
}
return validator.Validate(entity);
}
#endregion
}
I'm going to be using validation service in my controller. We could move it to the service layer and have StructureMap use property injection to inject an instance of controller's ModelState to the service layer, but i don't want the service layer to be coupled with ModelState. What if we decide to use another validation technique? This is why i'd rather put it in the controller. Here is what my controller looks like:
public class PostController : Controller
{
private IEntityService<Post> _service = null;
private IValidationService _validationService = null;
public PostController(IEntityService<Post> service, IValidationService validationService)
{
_service = service;
_validationService = validationService;
}
}
Here i am injecting my service layer and validaton service instances using StructureMap. So, we need to register both in StructureMap registry:
ForRequestedType<IValidationService>()
.TheDefaultIsConcreteType<ValidationService>();
ForRequestedType<IValidator<Post>>()
.TheDefaultIsConcreteType<PostValidator>();
That's it. I don't show how i implement my PostValidator, but it's simply implementing IValidator interface and defining validation logic in the Validate() method. All that's left to do is call your validation service instance to retrieve the validator, call the validate method on your entity and write any errors to ModelState.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "PostId")] Post post)
{
ValidationState vst = _validationService.Validate<Post>(post);
if (!vst.IsValid)
{
foreach (ValidationError error in vst.Errors)
{
this.ModelState.AddModelError(error.Property, error.Message);
}
return View(post);
}
...
}
Hope i helped somebody out with this :)
I used a similar solution involving a generic implementor of IValidationDictionary uses a StringDictionary and then copied the errors from this back into the model state in the controller.
Interface for validationdictionary
public interface IValidationDictionary
{
bool IsValid{get;}
void AddError(string Key, string errorMessage);
StringDictionary errors { get; }
}
Implementation of validation dictionary with no reference to model state or anything else so structuremap can create it easily
public class ValidationDictionary : IValidationDictionary
{
private StringDictionary _errors = new StringDictionary();
#region IValidationDictionary Members
public void AddError(string key, string errorMessage)
{
_errors.Add(key, errorMessage);
}
public bool IsValid
{
get { return (_errors.Count == 0); }
}
public StringDictionary errors
{
get { return _errors; }
}
#endregion
}
Code in the controller to copy the errors from the dictionary into the model state. This would probably be best as an extension function of Controller.
protected void copyValidationDictionaryToModelState()
{
// this copies the errors into viewstate
foreach (DictionaryEntry error in _service.validationdictionary.errors)
{
ModelState.AddModelError((string)error.Key, (string)error.Value);
}
}
thus bootstrapping code is like this
public static void BootstrapStructureMap()
{
// Initialize the static ObjectFactory container
ObjectFactory.Initialize(x =>
{
x.For<IContactRepository>().Use<EntityContactManagerRepository>();
x.For<IValidationDictionary>().Use<ValidationDictionary>();
x.For<IContactManagerService>().Use<ContactManagerService>();
});
}
and code to create controllers is like this
public class IocControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return (Controller)ObjectFactory.GetInstance(controllerType);
}
}
Just a quick query on this. It's helped me out quite a lot so thanks for putting the answer up, but I wondered which namespace TEntity exists in? I see Colletion(TEntity) needs System.Collections.ObjectModel. My file compiles without anything further but I see your TEntity reference highlighted in Blue which suggests it has a class type, mine is Black in Visual Studio. Hope you can help. I'm pretty keen to get this working.
Have you found any way to seperate validation into the service layer at all? My gut tells me that validating in the Controller is a bit smelly but I've looked high and low to find a way to pass validation error messages back to the controller without tightly coupling the service layer to the controller and can't find anything. :(
Again, thanks for the great post!
Lloyd

Resources