I'm using structure map as my IOC with web api and I have an injected dependency in my controller and it's concrete type also has a dependecy.
Controller
[RoutePrefix("api/products")]
public class ProductsController : BaseApiController
{
//private readonly ProductRepository _manageProducts;
private readonly IProductFactory _productFactory;
private readonly IGenericRepository _genericRepository;
public ProductsController(IProductFactory productFactory, IGenericRepository genericRepository)
{
_productFactory = productFactory;
_genericRepository = genericRepository;
//_manageProducts = new ProductRepository();
}
[Authorize]
[Route("addProduct")]
public IHttpActionResult AddNewProduct(ProductViewModels.AddProductViewModel product)
{
if (User.IsInRole("Admin"))
{
_productFactory.CreateProduct(product);
return Ok("Product Successfully Added");
}
return BadRequest("Your must have Administrator rights to perform the operation.");
}
}
Factory
public class ProductFactory : IProductFactory
{
private readonly IGenericRepository _genericRepository;
public ProductFactory(IGenericRepository genericRepository)
{
_genericRepository = genericRepository;
}
/// <summary>
/// Creates the product.
/// </summary>
/// <returns>The product.</returns>
/// <param name="viewModel">New product.</param>
public Product CreateProduct(ProductViewModels.AddProductViewModel viewModel)
{
var productToBeAdded = new Product
{
Title = viewModel.Title,
ISBN = viewModel.ISBN,
};
return productToBeAdded;
}
}
When I try to call product controller addproducts I get this runtime error for null reference exception:
{
"Message": "An error has occurred.",
"ExceptionMessage": "Object reference not set to an instance of an object.",
"ExceptionType": "System.NullReferenceException",
"StackTrace": " at ICEBookshop.API.Factories.ProductFactory.CreateProduct(AddProductViewModel viewModel) in C:\\Users\\GOWDY_N\\Source\\Repos\\ICEBookshop.API\\ICEBookshop.API\\P00603ClientApi\\Factories\\ProductFactory.cs:line 29\r\n at ICEBookshop.API.Controllers.ProductsController.AddNewProduct(AddProductViewModel product) in C:\\Users\\GOWDY_N\\Source\\Repos\\ICEBookshop.API\\ICEBookshop.API\\P00603ClientApi\\Controllers\\ProductsController.cs:line 95\r\n at lambda_method(Closure , Object , Object[] )\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}
This is what I've done with structuremap
public class DefaultRegistry : Registry
{
#region Constructors and Destructors
public DefaultRegistry()
{
Scan(
scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
For<IGenericRepository>().Use<GenericRepository<ApplicationDbContext>>();
For<IProductFactory>()
.Use<ProductFactory>()
.Ctor<IGenericRepository>()
.Is<GenericRepository<ApplicationDbContext>>().Named("DefaultInstanceKey");
#endregion
}
}
I thought this would fix it so it knows how to resolve my factory:
For<IProductFactory>()
.Use<ProductFactory>()
.Ctor<IGenericRepository>()
.Is<GenericRepository<ApplicationDbContext>>().Named("DefaultInstanceKey");
But it doesn't work neither. Does anyone know how to fix this?
Just register the two interfaces and their implementations. The framework will resolve the dependencies when resolving the target.
For<IGenericRepository>().Use<GenericRepository<ApplicationDbContext>>();
For<IProductFactory>().Use<ProductFactory>();
Related
I am trying to get a model property validation to work but allowing a null value in a string property.
The Property i'm trying to validate is a:
public string PhoneNumber { get; set;}
And i am validating it like this:
[Phone(ErrorMessage = "Invalid telephone number.")]
public string PhoneNumber { get; set;}
The validation works great in my case except for when a value is not sent in for Phone number, to the api with an object.
is there any thing like a: [AllowNullValue] attribute or how do i get null values pass the "Phone" attribute?
UPDATE (Anton Gorbunov's post):
{
"Message": "An error has occurred.",
"ExceptionMessage": "The field is not a valid phone number.",
"ExceptionType": "System.ComponentModel.DataAnnotations.ValidationException",
"StackTrace": " at System.ComponentModel.DataAnnotations.ValidationAttribute.Validate(Object value, String name)\r\n at RABE_BCV_API.Controllers.APIController.UpsertMember(MemberModel memberObject) in C:\\Users\\John\\Documents\\Visual Studio 2015\\Projects\\RABE_BCV_API\\RABE_BCV_API\\Controllers\\APIController.cs:line 29\r\n at lambda_method(Closure , Object , Object[] )\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}
It looks strange, because is the first instruction of IsValid Metod in PhoneAttribute is:
public override bool IsValid(object value) {
if (value == null) {
return true;
}
...
}
Maybe you use [Required] or [BindRequired] attributes?
I am trying to add Microsoft Extensions Dependency Injection to an existing ASP.NET WebApi/Owin project.
Following this blog post, I have added the ConfigureServices function, implemented DependencyResolver, and made HttpConfiguration instance to use it.
Also I added all the non-abstract controllers to DI, and ensured they are instantiated using the DI mechanism.
But after all these actions, requests to the application return error 500 with exception
Method not found: 'System.Net.Http.HttpRequestMessage System.Web.Http.Controllers.HttpActionContext.get_Request()'.
I get the same result even if I just add the Microsoft.Extensions.DependencyInjection package to NuGet and don't change any other code. After I remove it, everything works fine.
Here is the code I added into Startup.cs:
The DependcyResolver implementation:
public class DefaultDependencyResolver :
System.Web.Http.Dependencies.IDependencyResolver,
System.Web.Http.Dependencies.IDependencyScope
{
protected IServiceProvider serviceProvider;
public DefaultDependencyResolver(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public IDependencyScope BeginScope()
{
return this;
}
public void Dispose() { }
public object GetService(Type serviceType)
{
return this.serviceProvider.GetService(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this.serviceProvider.GetServices(serviceType);
}
}
Adding controllers to DI:
public void ConfigureServices(IServiceCollection services)
{
System.Diagnostics.Debugger.Launch();
IEnumerable<Type> controllers = typeof(Startup).Assembly.GetExportedTypes()
.Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition)
.Where(t => typeof(IController).IsAssignableFrom(t)
|| t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase));
foreach (var c in controllers)
{
services.AddTransient(c);
}
}
Creating ServiceCollection, calling services configuration and setting DependencyResolver:
public void Configuration(IAppBuilder app) {
// ...
HttpConfiguration httpConfiguration = new HttpConfiguration();
var services = new ServiceCollection();
ConfigureServices(services);
httpConfiguration.DependencyResolver =
new DefaultDependencyResolver(services.BuildServiceProvider());
WebApiConfig.Register(httpConfiguration);
app.UseWebApi(httpConfiguration);
}
The exception stacktrace:
at myCompany.myProduct.Controllers.SomeController.Get(String id, String offline)
at lambda_method(Closure , Object , Object[] )
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n
System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
You might need to add binding redirects to your web.config file.
Check the following links with more information on the issue:
https://github.com/Microsoft/BotBuilder/issues/3615
https://github.com/dotnet/standard/issues/481
https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/how-to-enable-and-disable-automatic-binding-redirection
I've installed 'System.Net.Http' from nuget (v 4.3.3) and updated my .csproj file to force msbuild to use specified dll:
<Reference Include="System.Net.Http, Version=4.1.1.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Net.Http.4.3.3\lib\net46\System.Net.Http.dll</HintPath>
</Reference>
It resolved the problem.
I ran in to a problem 6 days ago and i still can't figure it out.
I'm setting up a DBContext using DI:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddDbContext<ApplicationContext>(options =>
options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
The database file path is configurered in the appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=xxxx.db"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
And I'm creating a DBContext like this (https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext)
public class ApplicationContext : DbContext
{
public DbSet<Network> xxxx { get; set; }
public DbSet<NetworkEntry> xxxx { get; set; }
public ApplicationContext(DbContextOptions<ApplicationContext> options)
: base(options)
{ }
}
My controller code:
public JsonResult Index(ApplicationContext db)
{
return Json(db.Networks);
}
It compiles and runs. If I use the other way of configuring the DB, it works 100% problem free:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Filename=./blog.db");
}
The problem I'm having:
System.InvalidOperationException: Could not create a model binder for model object of type 'xxx.Data.ApplicationContext'.
at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory.CreateBinder(ModelBinderFactoryContext context)
at Microsoft.AspNetCore.Mvc.Internal.DefaultControllerArgumentBinder.<BindModelAsync>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Mvc.Internal.DefaultControllerArgumentBinder.<BindArgumentsCoreAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeNextResourceFilter>d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeAsync>d__20.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.<Invoke>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__7.MoveNext()
Any clues?
I have just solved a similar problem. The problem for me was that I'd misunderstood the dependency injection. The context doesn't get passed to the Controller method, but to the Controller's constructor.
public class NetworksController : Controller
{
private readonly ChoirAdminContext db;
public NetworksController(ApplicationContext context)
{
db = context;
}
public JsonResult Index()
{
return Json(db.Networks);
}
}
Currently I'm using this JsonFormatter to send camel-cased data to the client
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver();
WebApiConfig
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Web.Http;
namespace AlumCloud
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
((Newtonsoft.Json.Serialization.DefaultContractResolver)config.Formatters.JsonFormatter.SerializerSettings.ContractResolver).IgnoreSerializableAttribute = true;
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver();
}
}
}
Eveything works perfectly, my data is received on the client as expected perfectly.
Now, it is time to start sending data to the server and I am using the
C# Web Api in the .NET platform.
Here is the POST function I am attempting to post camel Cased JSON data to with the one C# object, I've removed most of the code for clarity.
WebApi Controller
namespace AlumCloud.Controllers
{
[Authorize]
public class HorizontalController : AlumCloudWebApiBaseController
{
public async Task<HttpResponseMessage> Post(Horizontal h)
{
string update = HttpContext.Current.Request.QueryString["a"];
int ownerID = 0; ;
HttpResponseMessage res = null;
InsertHorizontalHelper insertRes = null;
if (!int.TryParse(HttpContext.Current.Request.QueryString["id"], out ownerID))
{
return Request.CreateResponse(HttpStatusCode.NotFound, "Provide the id of the horizontal owner");
};
if (h.CompID < 1)
{
if (h.Sitelines.TopCompID > 0)
{
h.CompID = h.Sitelines.TopCompID;
};
}
switch (update)
{
Here is the way the Properties of the Horizontal object look like, they are Pascal Cased
C# Customer Object I want to map properties from JSON to C#
namespace CADDL.DataTransfer.Tables
{
[XmlType(Namespace = "urn:DataObjects")]
[XmlRoot(Namespace = "urn:DataObjects")]
[Serializable]
public class Horizontal : ColumnInfo, IHorizontal
{
[ColumnAttributes("ID", false, "int")]
public int ID { get; set; }
[ColumnAttributes("Position", false, "byte")]
public byte Position { get; set; }
[ColumnAttributes("Name", false, "string")]
public string Name { get; set; }
[ColumnAttributes("IsFiller", false, "bool")]
public bool IsFiller { get; set; }
[ColumnAttributes("HorizontalNote", false, "string")]
public string HorizontalNote { get; set; }
[ColumnAttributes("SizeID", false, "int")]
public int SizeID { get; set; }
[ColumnAttributes("WidthInches", false, "decimal")]
public decimal WidthInches { get; set; }
[ColumnAttributes("HeightInches", false, "decimal")]
My Error
{"message":"An error has occurred.","exceptionMessage":"Object reference not set to an instance of an object.","exceptionType":"System.NullReferenceException","stackTrace":" at AlumCloud.Controllers.HorizontalController.<Post>d__0.MoveNext() in D:\\Users\\Erik Little\\Documents\\visual studio 2015\\Projects\\AlumCloud\\AlumCloud\\Controllers\\CAD\\HorizontalController.cs:line 28\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Threading.Tasks.TaskHelpersExtensions.<CastToObject>d__3`1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"}
My questions to the group are.
Why is my Horizontal C# object always null is it because the JSON is Camel cased and the properties it is matching to is Pascal Cased?
Does the Properties mapper from the JSON to the C# object have to be the same case in order for the value to be set?
What is a global way to fix this issue so that I do not have to add attributes are setting in every new Web Api controller?
Just for clarity the attributes you see on each property are for my data layer, for when requesting data, they're not used in this instance
The way the objects are being received by the client and being processed on the server require two different objects to make life easier, so I've created a folder called client request and so there is no name clashes I've named the Horizontal class from the client size HorizontalRequest but with only the properties needed to satisfy the clients.
The class objects on the server are somewhat larger than what is needed to receive a JSON request so for when clients send data where server objects are 20 x larger than what is needed I'll just create classes like the HorizontalRequest, bare bone, no attributes, just properties.
I am trying to use ActionFilterAttribute to validate the model when a call is made to my Web API. I have added the following
public class ValidateModelStateAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
}
I have added standard validators to my model properties and it all works fine. However when I add a custom class level validator it fails with the following error.
A validation attribute of type XXXValidatorAttribute cannot be used to
validate values."
StackTrace: at
Microsoft.Practices.EnterpriseLibrary.Validation.Validators.BaseValidationAttribute.IsValid(Object
value)\r\n at
System.ComponentModel.DataAnnotations.ValidationAttribute.IsValid(Object
value, ValidationContext validationContext)\r\n at
System.ComponentModel.DataAnnotations.ValidationAttribute.GetValidationResult(Object
value, ValidationContext validationContext)\r\n at
System.Web.Http.Validation.Validators.DataAnnotationsModelValidator.Validate(ModelMetadata
metadata, Object container)\r\n at
System.Web.Http.Validation.DefaultBodyModelValidator.ShallowValidate(ModelMetadata
metadata, ValidationContext validationContext, Object container,
IEnumerable'1 validators)\r\n at
System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata
metadata, ValidationContext validationContext, Object container,
IEnumerable'1 validators)\r\n at
System.Web.Http.Validation.DefaultBodyModelValidator.Validate(Object
model, Type type, ModelMetadataProvider metadataProvider,
HttpActionContext actionContext, String keyPrefix)\r\n at
System.Web.Http.ModelBinding.FormatterParameterBinding.d__0.MoveNext()\r\n---
End of stack trace from previous location where exception was thrown
---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)\r\n at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)\r\n at
System.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n at
System.Web.Http.Controllers.HttpActionBinding.d__0.MoveNext()\r\n---
End of stack trace from previous location where exception was thrown
---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)\r\n at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)\r\n at
System.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n at
System.Web.Http.Controllers.ActionFilterResult.d__2.MoveNext()\r\n---
End of stack trace from previous location where exception was thrown
---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)\r\n at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)\r\n at
System.Runtime.CompilerServices.TaskAwaiter'1.GetResult()\r\n at
System.Web.Http.Controllers.AuthenticationFilterResult.d__0.MoveNext()\r\n---
End of stack trace from previous location where exception was thrown
---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)\r\n at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)\r\n at
System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at
System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()
This validator works fine when I invoke it via a unit test using a validation factory. I am not sure why it fails during ModelState validation? What is the difference between the two?
I have the model defined as
I have a model defined as
[CashDetailValidator()]
public sealed class CashDetails : DetailsBase
{
// Reference Number
[ValidatorComposition(CompositionType.Or)]
[NotNullValidator(Negated=true)]
[StringLengthValidator(1, RangeBoundaryType.Inclusive, 16, RangeBoundaryType.Exclusive, MessageTemplate = "Reference number should be between 1 to 16 characters in length.")]
public string RelatedReference { get; set; } ...........................
}}
The composition validator also gives the same error.