Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The type String cannot be constructed

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=&quot;data source=<REMOVED>;initial catalog=<REMOVED>;persist security info=True;user id=<REMOVED>;password=<REMOVED>;MultipleActiveResultSets=True;App=EntityFramework&quot;" 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

like image 601
Daniel M Avatar asked Aug 22 '13 19:08

Daniel M


3 Answers

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)
    {
    }
like image 181
user3221409 Avatar answered Oct 21 '22 16:10

user3221409


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.

like image 23
Felipe Oriani Avatar answered Oct 21 '22 17:10

Felipe Oriani


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;
    }
like image 6
Always Learning Avatar answered Oct 21 '22 17:10

Always Learning