I can't seem to figure out why AutoMapper is throwing an exception for this mapping:
public class MyDestinationType
{
public MyCustomEnum? PropName { get; set; }
}
public enum MyCustomEnum
{
Val1,
Val2
}
Mapper.CreateMap<MySourceType, MyDestinationType>()
.ForMember(d => d.PropName, o => o.ResolveUsing(s =>
{
if (s.Val1) return MyCustomEnum.Val1;
else if (s.Val2) return MyCustomEnum.Val2;
return null;
}))
;
The exception only occurs when the MyCustomEnum? PropName property gets mapped to a null value. Here is how I am doing the mapping:
var source = MethodToGetSourceObject();
var destination = Mapper.Map<MyDestinationType>(source);
The exception thrown is an AutoMapperMappingException which wraps 2 other AutoMapperMappingExceptions. The 4th and final InnerException is a NullReferenceException. The stack trace looks something like this:
[NullReferenceException: Object reference not set to an instance of an object.]
AutoMapper.Mappers.EnumMapper.Map(ResolutionContext context, IMappingEngineRunner mapper) +198
AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context) +447
[AutoMapperMappingException: Trying to map System.Object to System.Nullable`1[[MyProject.MyCustomEnum, MyProject, Version=2.0.4784.16259, Culture=neutral, PublicKeyToken=null]].
Using mapping configuration for MyProject.MySourceType to MyProject.MyDestinationType
Destination property: PropName
Exception of type 'AutoMapper.AutoMapperMappingException' was thrown.]
AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context) +519
AutoMapper.Mappers.PropertyMapMappingStrategy.MapPropertyValue(ResolutionContext context, IMappingEngineRunner mapper, Object mappedObject, PropertyMap propertyMap) +592
[AutoMapperMappingException: Trying to map System.Object to System.Nullable`1[[MyProject.MyCustomEnum, MyProject, Version=2.0.4784.16259, Culture=neutral, PublicKeyToken=null]].
Using mapping configuration for MyProject.MySourceType to MyProject.MyDestinationType
Destination property: PropName
Exception of type 'AutoMapper.AutoMapperMappingException' was thrown.]
AutoMapper.Mappers.PropertyMapMappingStrategy.MapPropertyValue(ResolutionContext context, IMappingEngineRunner mapper, Object mappedObject, PropertyMap propertyMap) +689
AutoMapper.Mappers.PropertyMapMappingStrategy.Map(ResolutionContext context, IMappingEngineRunner mapper) +275
AutoMapper.Mappers.TypeMapMapper.Map(ResolutionContext context, IMappingEngineRunner mapper) +273
AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context) +447
[AutoMapperMappingException: Trying to map MyProject.MySourceType to MyProject.MyDestinationType.
Using mapping configuration for MyProject.MySourceType to MyProject.MyDestinationType
Exception of type 'AutoMapper.AutoMapperMappingException' was thrown.]
AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context) +519
AutoMapper.MappingEngine.Map(Object source, Type sourceType, Type destinationType, Action`1 opts) +192
AutoMapper.MappingEngine.Map(Object source, Type sourceType, Type destinationType) +196
AutoMapper.MappingEngine.Map(Object source) +169
AutoMapper.Mapper.Map(Object source) +107
[Here is where my code calls Mapper.Map<MyDestinationType>(source)]
Again, the exception only occurs when the resolution would have PropName == null (for example if both s.Val1 and s.Val2 were false). The exception does not occur when the mapping would resolve to the enum having some non-null value.
Is this another bug in AutoMapper?
Related
I am trying to query an Oracle database from .NET7.
I used database first approach to generate my model context. When querying, I get the following exception:
InvalidCastException: Specified cast is not valid.
Oracle.ManagedDataAccess.Client.OracleDataReader.GetInt16(int i)...
That's my (truncated) object class, and the property causing the exception (when I comment the property, select query is working):
public partial class Car
{
public string? Owner { get; set; }
[...]
}
Database looks like this:
CREATE TABLE "Car"
( "Owner" VARCHAR2(6 BYTE)
[...]
Generated context:
modelBuilder.Entity<Car>(entity =>
{
entity.Property(e => e.Owner)
.HasMaxLength(6)
.IsUnicode(false)
.HasColumnName("Owner")
[...]
}
Packages:
Oracle.EntityFrameworkCore 7.21.8
Microsoft.EntityFrameworkCore.Design 7.0.1
What's the problem? Is it because the column is nullable? I have no idea.
EDIT:
Seems like the problem is the stored data. Some rows must be corrupted / not like the column definition.
EDIT2:
That's the LINQ query:
return await _context.Cars.Take(10).ToListAsync();
Stacktrace:
System.InvalidCastException: Specified cast is not valid.
at Oracle.ManagedDataAccess.Client.OracleDataReader.GetInt16(Int32 i)
at lambda_method19(Closure, QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at CarService.Controllers.CarController.GetCars(Int32 plate) in C:\GIT\webservices\car-service-dotnet\CarService\Controllers\CarController.cs:line 45
at lambda_method5(Closure, Object)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
I use ABP 5.1.0
.Net Core,
I have my class
ItemAsyncEventBaseHandler : IAsyncEventHandler<TEvent>, ITransientDependency
where TEvent : EventData {…}
Then i have class:
CustomHandler: ItemAsyncEventBaseHandler<EventData>
{
public CustomHandler(
IUnitOfWorkManager unitOfWorkManager,
ISettingManager settingManager)
{
_unitOfWorkManager = unitOfWorkManager;
_settingManager = settingManager;
}
}
public override async Task HandleInternallyAsync(ItemUpdatedEvent eventData)
{
await _settingManager.ChangeSettingForApplicationAsync("key", value.ToString());
}
At first glance, this works, but if I run the handler on two different items in quick succession, I get an error:
(On some machines it is enough to run the event on two items, on others it is necessary to run the event on the other two items in order for the same error to occur.)
System.ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'MyDbContext'.
at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed()
at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
at Microsoft.EntityFrameworkCore.DbContext.Set[TEntity]()
at Abp.EntityFrameworkCore.Repositories.EfCoreRepositoryBase`3.GetQueryable()
at Abp.EntityFrameworkCore.Repositories.EfCoreRepositoryBase`3.GetAllIncluding(Expression`1[] propertySelectors)
at Abp.EntityFrameworkCore.Repositories.EfCoreRepositoryBase`3.FirstOrDefaultAsync(Expression`1 predicate)
at Abp.Threading.InternalAsyncHelper.AwaitTaskWithPostActionAndFinallyAndGetResult[T](Task`1 actualReturnValue, Func`1 postAction, Action`1 finalAction)
at Abp.Configuration.SettingStore.GetSettingOrNullAsync(Nullable`1 tenantId, Nullable`1 userId, String name)
at Abp.Threading.InternalAsyncHelper.AwaitTaskWithPostActionAndFinallyAndGetResult[T](Task`1 actualReturnValue, Func`1 postAction, Action`1 finalAction)
at Abp.Configuration.SettingManager.InsertOrUpdateOrDeleteSettingValueAsync(String name, String value, Nullable`1 tenantId, Nullable`1 userId)
at Abp.Configuration.SettingManager.ChangeSettingForApplicationAsync(String name, String value)
at Abp.Threading.InternalAsyncHelper.AwaitTaskWithPostActionAndFinally(Task actualReturnValue, Func`1 postAction, Action`1 finalAction)
at Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException(Task task)
at Nito.AsyncEx.AsyncContext.<>c__DisplayClass15_0.<Run>b__0(Task t)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location where exception was thrown ---
at Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException(Task task)
at Nito.AsyncEx.AsyncContext.Run(Func`1 action)
And the value in the application settings is not updated.
I tried wrapping in uow but it doesn't help:
public override async Task HandleInternallyAsync(ItemUpdatedEvent eventData)
{
using (var uow = _unitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
{
await _settingManager.ChangeSettingForApplicationAsync("key", value.ToString());
await uow.CompleteAsync();
}
}
When trying to execute the following ASP.NET Core code:
public class Foo
{
public long A { get; set; }
public string B { get; set; }
}
[HttpGet]
[Route("Foos")]
public ActionResult<IEnumerable<IGrouping<long, Foo>>> Foos()
{
var foos = new List<Foo> { new Foo { A = 1, B = "Foo" }, new Foo { A = 2, B = "Bar" }, new Foo { A = 2, B = "Baz" } };
return new ActionResult<IEnumerable<IGrouping<long, Foo>>>(foos.GroupBy(f => f.A));
}
I get:
System.InvalidCastException: Unable to cast object of type 'Foo' to type 'System.Int64'.
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnWriteEnumerable(WriteStackFrame& current, Utf8JsonWriter writer)
at System.Text.Json.JsonPropertyInfo.WriteEnumerable(WriteStack& state, Utf8JsonWriter writer)
at System.Text.Json.JsonSerializer.HandleEnumerable(JsonClassInfo elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter writer, WriteStack& state)
at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json, Object value, Type inputType, JsonSerializerOptions options, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Why does it seem to be trying to serialize an object to an int64? How can I successfully return the result of a GroupBy from a web API endpoint?
New System.Text.Json serializer cannot serialize IEnumerable<IGrouping<long, Foo>>.
Solution
I would recommend switching to old Json.Net serializer in your ASP.Net Core project. I've tested it and it works fine with Json.Net.
See this article for information about switching to Json.Net.
It will be something as easy as that:
services.AddMvc()
.AddNewtonsoftJson();
I'm using Web.api and Unity and I am getting the following error when trying to open the default "help" area:
[InvalidOperationException: The type String cannot be constructed. You must configure the container to supply this value.]
Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.GuardTypeIsNonPrimitive(IBuilderContext context, SelectedConstructor selectedConstructor) +280
Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.PreBuildUp(IBuilderContext context) +356
Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +260
Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlanCreatorPolicy.CreatePlan(IBuilderContext context, NamedTypeBuildKey buildKey) +205
Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +231
Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +260
Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +250
Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context) +101
BuildUp_System.Web.Http.HttpRouteCollection(IBuilderContext ) +202
Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context) +42
Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +319
Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +260
Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +250
Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context) +101
BuildUp_System.Web.Http.HttpConfiguration(IBuilderContext ) +202
Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context) +42
Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +319
Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +260
Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +250
Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context) +101
BuildUp_API.Areas.HelpPage.Controllers.HelpController(IBuilderContext ) +204
Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context) +42
Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +319
Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +260
Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides) +373
[ResolutionFailedException: Resolution of the dependency failed, type = "API.Areas.HelpPage.Controllers.HelpController", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The type String cannot be constructed. You must configure the container to supply this value.
-----------------------------------------------
At the time of the exception, the container was:
Resolving API.Areas.HelpPage.Controllers.HelpController,(none)
Resolving parameter "config" of constructor API.Areas.HelpPage.Controllers.HelpController(System.Web.Http.HttpConfiguration config)
Resolving System.Web.Http.HttpConfiguration,(none)
Resolving parameter "routes" of constructor System.Web.Http.HttpConfiguration(System.Web.Http.HttpRouteCollection routes)
Resolving System.Web.Http.HttpRouteCollection,(none)
Resolving parameter "virtualPathRoot" of constructor System.Web.Http.HttpRouteCollection(System.String virtualPathRoot)
Resolving System.String,(none)
]
Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides) +436
Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, String name, IEnumerable`1 resolverOverrides) +50
Microsoft.Practices.Unity.UnityContainer.Resolve(Type t, String name, ResolverOverride[] resolverOverrides) +48
Microsoft.Practices.Unity.UnityContainerExtensions.Resolve(IUnityContainer container, Type t, ResolverOverride[] overrides) +61
Unity.Mvc4.UnityDependencyResolver.GetService(Type serviceType) +140
System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +87
[InvalidOperationException: An error occurred when trying to create a controller of type 'API.Areas.HelpPage.Controllers.HelpController'. Make sure that the controller has a parameterless public constructor.]
System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +247
System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +438
System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +226
System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +326
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +177
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +88
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +50
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +301
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155
I am new to unity and am sure I am missing step(s).
In webapiconfig.cs:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//Custom formatter
config.Formatters.Clear();
config.Formatters.Add(new JSONPFormater());
config.EnableSystemDiagnosticsTracing();
//Setup DI
Bootstrapper.Initialise();
}
Bootstraper.cs(default values)
public static class Bootstrapper
{
public static IUnityContainer Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
RegisterTypes(container);
return container;
}
public static void RegisterTypes(IUnityContainer container)
{
}
}
My attempt at a web.config
web.config
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>
<connectionStrings>
<add name="DefaultConnection" providerName="System.Data.SqlClient" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-API-20130708152001;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-API-20130708152001.mdf" />
<add name="<REMOVED>DBEntities" connectionString="metadata=res://*/Models.DAL.<REMOVED>.csdl|res://*/Models.DAL.<REMOVED>.ssdl|res://*/Models.DAL.<REMOVED>.msl;provider=System.Data.SqlClient;provider connection string="data source=<REMOVED>;initial catalog=<REMOVED>;persist security info=True;user id=<REMOVED>;password=<REMOVED>;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
<!--unity setting-->
<unity>
<containers>
<types>
<register type="API.Areas.HelpPage.Controllers.HelpController, API">
<constructor>
<param valu=""></param>
</constructor>
</register>
</types>
</containers>
</unity>
Am I headed in the right direction??
Thanks
Update:
helpcontroller.cs:
public class HelpController : Controller
{
public HelpController()
: this(GlobalConfiguration.Configuration)
{
}
public HelpController(HttpConfiguration config)
{
Configuration = config;
}
public HttpConfiguration Configuration { get; private set; }
public ActionResult Index()
{
return View(Configuration.Services.GetApiExplorer().ApiDescriptions);
}
public ActionResult Api(string apiId)
{
if (!String.IsNullOrEmpty(apiId))
{
HelpPageApiModel apiModel = Configuration.GetHelpPageApiModel(apiId);
if (apiModel != null)
{
return View(apiModel);
}
}
return View("Error");
}
}
url I am trying to access: http:// hostname:port/Help
I think a better way is to add InjectionConstructor attribute to the default constructor. This attribute forces unity to use the decorated constructor.
Example:
public class HelpController : Controller
{
private const string ErrorViewName = "Error";
[InjectionConstructor]
public HelpController()
: this(GlobalConfiguration.Configuration)
{
}
As your code sample, I'm assuming you are on a Controller and not a API Controller (from web api).
Your api controller has a dependency on the constructor from HttpConfiguration. The container problably does not have this definition for this type and consequently does not know how to solve it and the string on the error message should come from this type as a dependency. I recommend you use the GlobalConfiguration static class and access the Configuration property to get a HttpConfiguration instance. You could abstract it in a property, for sample:
// include this namespace
using System.Web.Http;
public class HelpController : Controller
{
// remove the constructors...
// property
protected static HttpConfiguration Configuration
{
get { return GlobalConfiguration.Configuration; }
}
public ActionResult Index()
{
return View(this.Configuration.Services.GetApiExplorer().ApiDescriptions);
}
public ActionResult Api(string apiId)
{
if (!String.IsNullOrEmpty(apiId))
{
HelpPageApiModel apiModel = this.Configuration.GetHelpPageApiModel(apiId);
if (apiModel != null)
{
return View(apiModel);
}
}
return View("Error");
}
}
Now, if you are on a Api Controller, you just can access directly the this.Configuration property that is already on the ApiController (base class for Api controllers) and get a instance of HttpConfiguration.
The reason this happens is because Unity will by default choose to use the constructor with the most parameters thus bypassing the default constructor.
Comment out the two constructors that exist in the HelpController template and add a default one that sets the configuration.
//public HelpController()
// : this(GlobalConfiguration.Configuration)
//{
//}
//public HelpController(HttpConfiguration config)
//{
// Configuration = config;
//}
public HelpController()
{
Configuration = GlobalConfiguration.Configuration;
}
Registering the HttpConfiguration object as an instance in UnityContainer will also help resolve the issue.
Just need to add to add the below line while registering in UnityContainer.
public static void RegisterTypes(IUnityContainer container) {
container.RegisterInstance<HttpConfiguration>(GlobalConfiguration.Configuration);
}
This will help Unity resolve the config parameter, when it invokes the constructor with the parameter.
public HelpController(HttpConfiguration config) {
Configuration = config;
}
I've recently had this error happen on a previously working codebase. The following answer shows what I did to correct it:
Adding Web API and API documentation to an existing MVC project
Basically make the constructor with parameters protected rather than public
OS: Windows vista, Framework: Spring (latest), JQuery (latest), Hibernate (latest).
I have a domain class with primary key as long id.
public class domain{
private long id;
....
}
My Controller definition:
#RequestMapping("/domainJqgridData/save")
public #ResponseBody String saveJqgridData(DomainClass domainclass) throws Exception {
return "Saved successfully!";
}
When the JSP form is submitted to add a new DomainClass record, the Spring controller tries to automatically bind the request parameters to domain class. It throws a BindException as follows:
Request processing failed; nested exception is org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'domain' on field 'id': rejected value [_empty]; codes [typeMismatch.domainclass.id,typeMismatch.id,typeMismatch.long,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [domainclass.id,id]; arguments []; default message [id]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'long' for property 'id'; nested exception is org.springframework.core.convert.ConversionFailedException: Unable to convert value "_empty" from type 'java.lang.String' to type 'long'; nested exception is java.lang.NumberFormatException: For input string: "_empty"]
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:656)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
As I am adding a new DomainClass record, the id field is passed as null by the JSP form. Spring converts the null id to empty string value for binding purpose and throws the error. I browsed the net and found that I can register custom editors for such purpose. I changed the DomainClass primitive type definition long id, to Long id and tried to bind a custom editor as follows.
Controller class:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Long.class, new CustomPrimitiveFormat(Long.class, true));
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}
My custom primitive editor class is as follows:
public class CustomPrimitiveFormat extends CustomNumberEditor{
public CustomPrimitiveFormat(Class numberClass, boolean allowEmpty)
throws IllegalArgumentException {
super(numberClass, allowEmpty);
// TODO Auto-generated constructor stub
}
public void setValue(Object value){
System.out.println("Entered CustomPrimitiveFormat setValue");
if (value == null) {
super.setValue(null);
return;
}
if (value.getClass().equals(String.class)){
if (StringUtils.isEmpty((String)value)){
super.setValue(null);
}
}
}
public void setAsText(Object value){
System.out.println("Entered CustomPrimitiveFormat setAsText");
if (value == null) {
super.setValue(null);
return;
}
if (value.getClass().equals(String.class)){
if (StringUtils.isEmpty((String)value)){
super.setValue(null);
}
}
}
}
I still receive the BindingException. Could not find any link that would guide me through how to overcome Spring BindException when adding a new Domain class record. I would like my primary key to remain primitive type, instead of using the Number object type.
Thanks in advance for your help.
As you can see in the error message, jqGrid uses _empty as an id of the new record (also see here), so you need to change your PropertyEditor to convert _empty to null.