I am getting the following exception when program.cs calls CreateHostBuilder.Build():
System.InvalidOperationException : Unable to resolve service for type 'web_application.Models.postStatus' while attempting to activate 'web_application.Services.Updates.PostingStatusUpdater'.
Full error below, but it is being thrown at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
I searched for ways to turn on verbose logging for that dependency injection dll or ways to debug the dependency injection framework and couldn't find answers to that. If anyone knows how to enable verbose logging at this stage of the program, please free to help too! This is how the service is being registered in Startup.cs:
using System;
...
namespace web_application
{
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IUpdateService<postStatus>, PostingStatusUpdater>();
...
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
...
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
}
}
postStatus is an enum, and my first thought was maybe DI registration was failing because of something related to it.
The actual class being registered derives from a base class, which implements the generic interface.
Generic Interface:
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using web_application.Models;
namespace web_application.Services.Updates{
public interface IUpdateService<T>{
bool runPreUpdateChecks(out IList<string> allFailedChecks);
void runPostCheckHooks();
bool tryPerformUpdate(T intialState, T FinalState, Action runUpdate, out IList<string> failureReasons);
Task<(bool success, IList<string> updateFailureReasons)> tryPerformUpdateAsync(T intialState, T FinalState, Task runUpdateAsync);
}
}
The base class:
using System;
using System.Threading.Tasks;
using web_application.Models;
using System.Collections.Generic;
namespace web_application.Services.Updates{
public abstract class BaseStatusUpdater<T> : IUpdateService<T>
{
public T initStatus {get; private set;}
public T finalStatus {get; private set;}
// TODO: Add update check attributes
public List<PreUpdateCheck<T>> preUpdateChecks = new List<PreUpdateCheck<T>>();
public IList<Action> postUpdateHooks = new List<Action>();
public BaseStatusUpdater(T initStatus, T finalStatus){
this.initStatus = initStatus;
this.finalStatus = finalStatus;
}
/// <summary>
/// Runs preupdate checks and returns every check that failed (no short circuit)
/// Returns a list of failed checks on failure.
/// </summary>
public bool runPreUpdateChecks(out IList<string> allFailedChecks){
allFailedChecks = new List<string>(preUpdateChecks.Count);
var allChecksPassed = true;
foreach(var check in preUpdateChecks){
if(!check.run()){
allFailedChecks.Add(check.failureReason);
allChecksPassed = false;
}
}
return allChecksPassed;
}
/// <summary>
/// Run only actions that are one-off, and don't cascade into other
/// actions that may require custom error handling.
/// </summary>
public void runPostCheckHooks(){
foreach(var hook in postUpdateHooks){
hook();
}
}
public bool tryPerformUpdate(T intialState, T FinalState, Action runUpdate, out IList<string> updateFailureReasons){
if(!runPreUpdateChecks(out updateFailureReasons)){
return false;
}
runUpdate();
runPostCheckHooks();
return true;
}
// https://stackoverflow.com/questions/18716928/how-to-write-an-async-method-with-out-parameter
public async Task<(bool success, IList<string> updateFailureReasons)>
tryPerformUpdateAsync(T intialState, T FinalState, Task runUpdateAsync)
{
IList<string> updateFailureReasons = new List<string>(preUpdateChecks.Count);
if(!runPreUpdateChecks(out updateFailureReasons)){
return (false,updateFailureReasons);
}
await runUpdateAsync;
runPostCheckHooks();
return (true,updateFailureReasons);
}
}
}
The class being registered for IUpdateService
using System;
using web_application.Models;
using System.Collections.Generic;
namespace web_application.Services.Updates{
// Make this a singleton on injection to get this so that we don't keep constructing the things
// in the constructor every time its called? Or store the static logic somewhere else
using vpStatus = postStatus;
public class PostingStatusUpdater : BaseStatusUpdater<postStatus>
{
public PostingStatusUpdater(vpStatus vpsInitial, vpStatus vpsFinal)
: base(vpsInitial,vpsFinal)
{
Func<(bool,string)> isMovePermitted = () => {
if(UpdateLogic.permittedStatusChanges
.Contains(new UpdateLogic.statusPair(base.initStatus, vpsFinal))){
return (true,string.Empty);
}
return (false, "Cannot mark post as \"" + vpsFinal.ToString() + " since it is currently marked as "
+ "\"" + vpsInitial.ToString() + "\"");
};
var check1 = new PreUpdateCheck<vpStatus>(isMovePermitted);
base.preUpdateChecks.Add(check1);
}
}
}
There is not compile time error or warning about this, and I've been digging around to make sure this hasn't been addressed before but I can't find a question that addresses this exactly, so I thought I'd post this for help.
Thanks.
Full error:
Exception thrown: 'System.AggregateException' in Microsoft.Extensions.DependencyInjection.dll: 'Some services are not able to be constructed' Inner exceptions found, see $exception in variables window for more details. Innermost exception System.InvalidOperationException : Unable to resolve service for type 'web_application.Models.postStatus' while attempting to activate 'web_application.Services.Updates.PostingStatusUpdater'. at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.ValidateService(ServiceDescriptor descriptor)