Replace calls to GetService<T> with GetRequiredService<T>

Even though GetService<T> still exists, GetRequiredService<T> preserves
the old behavior of throwing for missing services.
This commit is contained in:
Stephen Halter 2014-10-16 12:02:04 -07:00
parent 54ac14fa0f
commit a21ed4bc51
38 changed files with 65 additions and 59 deletions

View File

@ -74,7 +74,7 @@ namespace MvcSample.Web
});
var valueProviderFactory = context.RouteContext.HttpContext.RequestServices
.GetService<ICompositeValueProviderFactory>();
.GetRequiredService<ICompositeValueProviderFactory>();
var factoryContext = new ValueProviderFactoryContext(
context.RouteContext.HttpContext,

View File

@ -94,7 +94,7 @@ namespace Microsoft.AspNet.Mvc
var defaultFormatters = formatterContext.ActionContext
.HttpContext
.RequestServices
.GetService<IOutputFormattersProvider>()
.GetRequiredService<IOutputFormattersProvider>()
.OutputFormatters;
var formatter = _objectResult.SelectFormatter(formatterContext, defaultFormatters);
@ -103,7 +103,7 @@ namespace Microsoft.AspNet.Mvc
formatter = _defaultFormatter ?? formatterContext.ActionContext
.HttpContext
.RequestServices
.GetService<JsonOutputFormatter>();
.GetRequiredService<JsonOutputFormatter>();
}
return formatter;

View File

@ -209,7 +209,7 @@ namespace Microsoft.AspNet.Mvc
{
formatters = context.HttpContext
.RequestServices
.GetService<IOutputFormattersProvider>()
.GetRequiredService<IOutputFormattersProvider>()
.OutputFormatters;
}
else

View File

@ -34,7 +34,7 @@ namespace Microsoft.AspNet.Mvc
var destinationUrl = Url;
var urlHelper = context.HttpContext
.RequestServices
.GetService<IUrlHelper>();
.GetRequiredService<IUrlHelper>();
// IsLocalUrl is called to handle Urls starting with '~/'.
if (urlHelper.IsLocalUrl(destinationUrl))

View File

@ -25,7 +25,7 @@ namespace Microsoft.AspNet.Mvc
public override async Task ExecuteResultAsync([NotNull] ActionContext context)
{
var viewEngine = ViewEngine ?? context.HttpContext.RequestServices.GetService<ICompositeViewEngine>();
var viewEngine = ViewEngine ?? context.HttpContext.RequestServices.GetRequiredService<ICompositeViewEngine>();
var viewName = ViewName ?? context.ActionDescriptor.Name;
var view = FindViewInternal(viewEngine, context, viewName);

View File

@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Mvc
public AntiForgeryToken GetCookieToken(HttpContext httpContext)
{
var contextAccessor = httpContext.RequestServices.GetService<IContextAccessor<AntiForgeryContext>>();
var contextAccessor = httpContext.RequestServices.GetRequiredService<IContextAccessor<AntiForgeryContext>>();
if (contextAccessor.Value != null)
{
return contextAccessor.Value.CookieToken;
@ -57,7 +57,7 @@ namespace Microsoft.AspNet.Mvc
{
// Add the cookie to the request based context.
// This is useful if the cookie needs to be reloaded in the context of the same request.
var contextAccessor = httpContext.RequestServices.GetService<IContextAccessor<AntiForgeryContext>>();
var contextAccessor = httpContext.RequestServices.GetRequiredService<IContextAccessor<AntiForgeryContext>>();
Contract.Assert(contextAccessor.Value == null, "AntiForgeryContext should be set only once per request.");
contextAccessor.SetValue(new AntiForgeryContext() { CookieToken = token });

View File

@ -68,7 +68,7 @@ namespace Microsoft.AspNet.Mvc
{
_viewEngine = ActionContext?.
HttpContext?.
RequestServices.GetService<ICompositeViewEngine>();
RequestServices.GetRequiredService<ICompositeViewEngine>();
}
return _viewEngine;

View File

@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Mvc
private ActionDescriptorsCollection GetCollection()
{
var actionDescriptorProvider =
_serviceProvider.GetService<INestedProviderManager<ActionDescriptorProviderContext>>();
_serviceProvider.GetRequiredService<INestedProviderManager<ActionDescriptorProviderContext>>();
var actionDescriptorProviderContext = new ActionDescriptorProviderContext();
actionDescriptorProvider.Invoke(actionDescriptorProviderContext);

View File

@ -72,7 +72,7 @@ namespace Microsoft.AspNet.Mvc
{
var serviceProvider = context.HttpContext.RequestServices;
return new ViewDataDictionary(
serviceProvider.GetService<IModelMetadataProvider>(),
serviceProvider.GetRequiredService<IModelMetadataProvider>(),
context.ModelState);
}
}

View File

@ -60,7 +60,7 @@ namespace Microsoft.AspNet.Mvc
}
else
{
var authorizationService = httpContext.RequestServices.GetService<IAuthorizationService>();
var authorizationService = httpContext.RequestServices.GetRequiredService<IAuthorizationService>();
if (authorizationService == null)
{

View File

@ -25,7 +25,7 @@ namespace Microsoft.AspNet.Mvc
public IFilter CreateInstance([NotNull] IServiceProvider serviceProvider)
{
var activator = serviceProvider.GetService<ITypeActivator>();
var activator = serviceProvider.GetRequiredService<ITypeActivator>();
var obj = activator.CreateInstance(serviceProvider, ImplementationType, Arguments ?? new object[0]);
var filter = obj as IFilter;

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Mvc
public IFilter CreateInstance(IServiceProvider serviceProvider)
{
var antiForgery = serviceProvider.GetService<AntiForgery>();
var antiForgery = serviceProvider.GetRequiredService<AntiForgery>();
return new ValidateAntiForgeryTokenAuthorizationFilter(antiForgery);
}
}

View File

@ -65,7 +65,7 @@ namespace Microsoft.AspNet.Mvc
if (property.PropertyType.IsAssignableFrom(typeof(TProperty)))
{
property.SetValue(obj, services.GetService<TProperty>());
property.SetValue(obj, services.GetRequiredService<TProperty>());
}
}
}

View File

@ -71,7 +71,7 @@ namespace Microsoft.AspNet.Mvc
private static ActionDescriptorsCollection GetAndValidateActionDescriptorsCollection(HttpContext httpContext)
{
var provider = httpContext.RequestServices
.GetService<IActionDescriptorsCollectionProvider>();
.GetRequiredService<IActionDescriptorsCollectionProvider>();
var descriptors = provider.ActionDescriptors;
if (descriptors == null)

View File

@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Mvc
{
// The contract of this method is to check that the values coming in from the route are valid;
// that they match an existing action, setting IsBound = true if the values are OK.
var actionSelector = context.Context.RequestServices.GetService<IActionSelector>();
var actionSelector = context.Context.RequestServices.GetRequiredService<IActionSelector>();
context.IsBound = actionSelector.HasValidAction(context);
// We return null here because we're not responsible for generating the url, the route is.
@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Mvc
EnsureLogger(context.HttpContext);
using (_logger.BeginScope("MvcRouteHandler.RouteAsync"))
{
var actionSelector = services.GetService<IActionSelector>();
var actionSelector = services.GetRequiredService<IActionSelector>();
var actionDescriptor = await actionSelector.SelectAsync(context);
if (actionDescriptor == null)
@ -78,13 +78,13 @@ namespace Microsoft.AspNet.Mvc
var actionContext = new ActionContext(context.HttpContext, context.RouteData, actionDescriptor);
var optionsAccessor = services.GetService<IOptions<MvcOptions>>();
var optionsAccessor = services.GetRequiredService<IOptions<MvcOptions>>();
actionContext.ModelState.MaxAllowedErrors = optionsAccessor.Options.MaxModelValidationErrors;
var contextAccessor = services.GetService<IContextAccessor<ActionContext>>();
var contextAccessor = services.GetRequiredService<IContextAccessor<ActionContext>>();
using (contextAccessor.SetContextSource(() => actionContext, PreventExchange))
{
var invokerFactory = services.GetService<IActionInvokerFactory>();
var invokerFactory = services.GetRequiredService<IActionInvokerFactory>();
var invoker = invokerFactory.CreateInvoker(actionContext);
if (invoker == null)
{
@ -134,7 +134,7 @@ namespace Microsoft.AspNet.Mvc
{
if (_logger == null)
{
var factory = context.RequestServices.GetService<ILoggerFactory>();
var factory = context.RequestServices.GetRequiredService<ILoggerFactory>();
_logger = factory.Create<MvcRouteHandler>();
}
}

View File

@ -124,8 +124,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
var result = new StringBuilder();
var serviceProvider = html.ViewContext.HttpContext.RequestServices;
var metadataProvider = serviceProvider.GetService<IModelMetadataProvider>();
var viewEngine = serviceProvider.GetService<ICompositeViewEngine>();
var metadataProvider = serviceProvider.GetRequiredService<IModelMetadataProvider>();
var viewEngine = serviceProvider.GetRequiredService<ICompositeViewEngine>();
var index = 0;
foreach (var item in collection)
@ -217,7 +217,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
var serviceProvider = html.ViewContext.HttpContext.RequestServices;
var viewEngine = serviceProvider.GetService<ICompositeViewEngine>();
var viewEngine = serviceProvider.GetRequiredService<ICompositeViewEngine>();
foreach (var propertyMetadata in modelMetadata.Properties.Where(pm => ShouldShow(pm, templateInfo)))
{

View File

@ -84,8 +84,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
var result = new StringBuilder();
var serviceProvider = html.ViewContext.HttpContext.RequestServices;
var metadataProvider = serviceProvider.GetService<IModelMetadataProvider>();
var viewEngine = serviceProvider.GetService<ICompositeViewEngine>();
var metadataProvider = serviceProvider.GetRequiredService<IModelMetadataProvider>();
var viewEngine = serviceProvider.GetRequiredService<ICompositeViewEngine>();
var index = 0;
foreach (var item in collection)
@ -225,7 +225,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
var serviceProvider = html.ViewContext.HttpContext.RequestServices;
var viewEngine = serviceProvider.GetService<ICompositeViewEngine>();
var viewEngine = serviceProvider.GetRequiredService<ICompositeViewEngine>();
foreach (var propertyMetadata in modelMetadata.Properties.Where(pm => ShouldShow(pm, templateInfo)))
{

View File

@ -197,7 +197,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
private static IHtmlHelper MakeHtmlHelper(ViewContext viewContext, ViewDataDictionary viewData)
{
var newHelper = viewContext.HttpContext.RequestServices.GetService<IHtmlHelper>();
var newHelper = viewContext.HttpContext.RequestServices.GetRequiredService<IHtmlHelper>();
var contextable = newHelper as ICanHasViewContext;
if (contextable != null)

View File

@ -28,7 +28,7 @@ namespace Microsoft.AspNet.Mvc.Routing
{
var actions = GetActionDescriptors(services);
var inlineConstraintResolver = services.GetService<IInlineConstraintResolver>();
var inlineConstraintResolver = services.GetRequiredService<IInlineConstraintResolver>();
var routeInfos = GetRouteInfos(inlineConstraintResolver, actions);
// We're creating one AttributeRouteGenerationEntry per action. This allows us to match the intended
@ -79,12 +79,12 @@ namespace Microsoft.AspNet.Mvc.Routing
target,
matchingEntries,
generationEntries,
services.GetService<ILoggerFactory>());
services.GetRequiredService<ILoggerFactory>());
}
private static IReadOnlyList<ActionDescriptor> GetActionDescriptors(IServiceProvider services)
{
var actionDescriptorProvider = services.GetService<IActionDescriptorsCollectionProvider>();
var actionDescriptorProvider = services.GetRequiredService<IActionDescriptorsCollectionProvider>();
var actionDescriptorsCollection = actionDescriptorProvider.ActionDescriptors;
return actionDescriptorsCollection.Items;

View File

@ -74,7 +74,7 @@ namespace Microsoft.AspNet.Mvc
private object CreateComponent([NotNull] ViewContext context)
{
var activator = _serviceProvider.GetService<ITypeActivator>();
var activator = _serviceProvider.GetRequiredService<ITypeActivator>();
var component = activator.CreateInstance(_serviceProvider, _componentType.AsType());
_viewComponentActivator.Activate(component, context);
return component;

View File

@ -21,8 +21,8 @@ namespace Microsoft.AspNet.Mvc.Razor
public RazorPreCompiler([NotNull] IServiceProvider designTimeServiceProvider) :
this(designTimeServiceProvider,
designTimeServiceProvider.GetService<IMvcRazorHost>(),
designTimeServiceProvider.GetService<IOptions<RazorViewEngineOptions>>())
designTimeServiceProvider.GetRequiredService<IMvcRazorHost>(),
designTimeServiceProvider.GetRequiredService<IOptions<RazorViewEngineOptions>>())
{
}
@ -34,7 +34,7 @@ namespace Microsoft.AspNet.Mvc.Razor
_host = host;
_host.EnableInstrumentation = true;
var appEnv = _serviceProvider.GetService<IApplicationEnvironment>();
var appEnv = _serviceProvider.GetRequiredService<IApplicationEnvironment>();
_fileSystem = optionsAccessor.Options.FileSystem;
}

View File

@ -119,7 +119,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{
if (_tagHelperActivator == null)
{
_tagHelperActivator = ViewContext.HttpContext.RequestServices.GetService<ITagHelperActivator>();
_tagHelperActivator = ViewContext.HttpContext.RequestServices.GetRequiredService<ITagHelperActivator>();
}
return _tagHelperActivator;
@ -393,7 +393,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{
if (_urlHelper == null)
{
_urlHelper = Context.RequestServices.GetService<IUrlHelper>();
_urlHelper = Context.RequestServices.GetRequiredService<IUrlHelper>();
}
return _urlHelper.Content(contentPath);

View File

@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{
if (_provider == null)
{
_provider = Context.RequestServices.GetService<IModelMetadataProvider>();
_provider = Context.RequestServices.GetRequiredService<IModelMetadataProvider>();
}
var name = ExpressionHelper.GetExpressionText(expression);

View File

@ -183,7 +183,7 @@ namespace Microsoft.AspNet.Mvc.Razor
// and might store state. We'll use the service container to create new instances as we require.
var services = actionContext.HttpContext.RequestServices;
var view = services.GetService<IRazorView>();
var view = services.GetRequiredService<IRazorView>();
view.Contextualize(page, partial);
return ViewEngineResult.Found(viewName, view);

View File

@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Mvc.Razor
// it is ok to use the cached service provider because both this, and the
// resolved service are in a lifetime of Scoped.
// We don't want to get it upgront because it will force Roslyn to load.
_razorcompilationService = _serviceProvider.GetService<IRazorCompilationService>();
_razorcompilationService = _serviceProvider.GetRequiredService<IRazorCompilationService>();
}
return _razorcompilationService;

View File

@ -107,10 +107,10 @@ namespace System.Web.Http
/// </param>
public void Validate<TEntity>(TEntity entity, string keyPrefix)
{
var validator = Context.RequestServices.GetService<IBodyModelValidator>();
var metadataProvider = Context.RequestServices.GetService<IModelMetadataProvider>();
var validator = Context.RequestServices.GetRequiredService<IBodyModelValidator>();
var metadataProvider = Context.RequestServices.GetRequiredService<IModelMetadataProvider>();
var modelMetadata = metadataProvider.GetMetadataForType(() => entity, typeof(TEntity));
var validatorProvider = Context.RequestServices.GetService<ICompositeModelValidatorProvider>();
var validatorProvider = Context.RequestServices.GetRequiredService<ICompositeModelValidatorProvider>();
var modelValidationContext = new ModelValidationContext(metadataProvider,
validatorProvider,
ModelState,

View File

@ -214,11 +214,11 @@ namespace System.Net.Http
if (formatters == null)
{
// Get the default formatters from options
var options = context.RequestServices.GetService<IOptions<WebApiCompatShimOptions>>();
var options = context.RequestServices.GetRequiredService<IOptions<WebApiCompatShimOptions>>();
formatters = options.Options.Formatters;
}
var contentNegotiator = context.RequestServices.GetService<IContentNegotiator>();
var contentNegotiator = context.RequestServices.GetRequiredService<IContentNegotiator>();
var result = contentNegotiator.Negotiate(typeof(T), request, formatters);
if (result?.Formatter == null)
@ -266,7 +266,7 @@ namespace System.Net.Http
var context = GetHttpContext(request);
// Get the default formatters from options
var options = context.RequestServices.GetService<IOptions<WebApiCompatShimOptions>>();
var options = context.RequestServices.GetRequiredService<IOptions<WebApiCompatShimOptions>>();
var formatters = options.Options.Formatters;
var formatter = formatters.FindWriter(typeof(T), mediaType);

View File

@ -108,7 +108,7 @@ namespace Microsoft.AspNet.Mvc
// The host is designed to be discarded after consumption and is very inexpensive to initialize.
yield return describe.Transient<IMvcRazorHost>(serviceProvider =>
{
var optionsAccessor = serviceProvider.GetService<IOptions<RazorViewEngineOptions>>();
var optionsAccessor = serviceProvider.GetRequiredService<IOptions<RazorViewEngineOptions>>();
return new MvcRazorHost(optionsAccessor.Options.FileSystem);
});

View File

@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Mvc
public virtual void BeforeCompile(IBeforeCompileContext context)
{
var sc = new ServiceCollection();
var appEnv = _appServices.GetService<IApplicationEnvironment>();
var appEnv = _appServices.GetRequiredService<IApplicationEnvironment>();
var setup = new RazorViewEngineOptionsSetup(appEnv);
var accessor = new OptionsManager<RazorViewEngineOptions>(new[] { setup });

View File

@ -21,6 +21,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test
var services = new Mock<IServiceProvider>();
services.Setup(s => s.GetService(typeof(IUrlHelper)))
.Returns(Mock.Of<IUrlHelper>());
services.Setup(s => s.GetService(typeof(IModelMetadataProvider)))
.Returns(Mock.Of<IModelMetadataProvider>());
var httpRequest = Mock.Of<HttpRequest>();
var httpContext = new Mock<HttpContext>();
@ -83,6 +85,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test
var services = new Mock<IServiceProvider>();
services.Setup(s => s.GetService(typeof(IUrlHelper)))
.Returns(urlHelper);
services.Setup(s => s.GetService(typeof(IModelMetadataProvider)))
.Returns(Mock.Of<IModelMetadataProvider>());
var httpContext = new Mock<HttpContext>();
httpContext.SetupGet(c => c.RequestServices)
@ -109,6 +113,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test
var services = new Mock<IServiceProvider>();
services.Setup(s => s.GetService(typeof(IUrlHelper)))
.Returns(Mock.Of<IUrlHelper>());
services.Setup(s => s.GetService(typeof(IModelMetadataProvider)))
.Returns(Mock.Of<IModelMetadataProvider>());
var httpContext = new Mock<HttpContext>();
httpContext.SetupGet(c => c.Response)

View File

@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
[Fact]
public async Task RoutingToANonExistantArea_WithExistConstraint_RoutesToCorrectAction()
{
var svc = _provider.GetService<ICommandLineArgumentBuilder>();
var svc = _provider.GetRequiredService<ICommandLineArgumentBuilder>();
svc.AddArgument("--TemplateCollection:areaRoute:TemplateValue=" +
"{area:exists}/{controller=Home}/{action=Index}");
svc.AddArgument("--TemplateCollection:actionAsMethod:TemplateValue=" +
@ -51,7 +51,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
public async Task RoutingToANonExistantArea_WithoutExistConstraint_RoutesToIncorrectAction()
{
// Arrange
var svc = _provider.GetService<ICommandLineArgumentBuilder>();
var svc = _provider.GetRequiredService<ICommandLineArgumentBuilder>();
svc.AddArgument("--TemplateCollection:areaRoute:TemplateValue=" +
"{area}/{controller=Home}/{action=Index}");
svc.AddArgument("--TemplateCollection:actionAsMethod:TemplateValue" +

View File

@ -25,7 +25,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
public static IServiceProvider CreateServices(string applicationWebSiteName, string applicationPath)
{
var originalProvider = CallContextServiceLocator.Locator.ServiceProvider;
var appEnvironment = originalProvider.GetService<IApplicationEnvironment>();
var appEnvironment = originalProvider.GetRequiredService<IApplicationEnvironment>();
// When an application executes in a regular context, the application base path points to the root
// directory where the application is located, for example MvcSample.Web. However, when executing

View File

@ -56,7 +56,7 @@ namespace ConnegWebsite
public IActionResult OverrideTheFallback_WithDefaultFormatters(int input)
{
var objectResult = new ObjectResult(input);
var formattersProvider = ActionContext.HttpContext.RequestServices.GetService<IOutputFormattersProvider>();
var formattersProvider = ActionContext.HttpContext.RequestServices.GetRequiredService<IOutputFormattersProvider>();
objectResult.Formatters.Add(new HttpNotAcceptableOutputFormatter());
foreach (var formatter in formattersProvider.OutputFormatters)
{

View File

@ -20,7 +20,7 @@ namespace InlineConstraints
configuration.AddEnvironmentVariables();
var commandLineBuilder = app.ApplicationServices.GetService<ICommandLineArgumentBuilder>();
var commandLineBuilder = app.ApplicationServices.GetRequiredService<ICommandLineArgumentBuilder>();
string appConfigPath;
if (configuration.TryGet("AppConfigPath", out appConfigPath))
{
@ -33,7 +33,7 @@ namespace InlineConstraints
}
else
{
var basePath = app.ApplicationServices.GetService<IApplicationEnvironment>().ApplicationBasePath;
var basePath = app.ApplicationServices.GetRequiredService<IApplicationEnvironment>().ApplicationBasePath;
configuration.AddJsonFile(Path.Combine(basePath, @"App_Data\config.json"));
}

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Builder
{
public static Configuration GetTestConfiguration(this IApplicationBuilder app)
{
var configurationProvider = app.ApplicationServices.GetService<ITestConfigurationProvider>();
var configurationProvider = app.ApplicationServices.GetRequiredService<ITestConfigurationProvider>();
var configuration = configurationProvider == null
? new Configuration()
: configurationProvider.Configuration;

View File

@ -27,7 +27,7 @@ namespace RazorInstrumentationWebSite
{
if (!string.IsNullOrEmpty(context.Request.Headers["ENABLE-RAZOR-INSTRUMENTATION"]))
{
var pageExecutionContext = context.ApplicationServices.GetService<TestPageExecutionContext>();
var pageExecutionContext = context.ApplicationServices.GetRequiredService<TestPageExecutionContext>();
var listenerFeature = new TestPageExecutionListenerFeature(pageExecutionContext);
context.SetFeature<IPageExecutionListenerFeature>(listenerFeature);
}

View File

@ -33,7 +33,7 @@ namespace RoutingWebSite
.Where(kvp => kvp.Key != "link" && kvp.Key != "link_action" && kvp.Key != "link_controller")
.ToDictionary(kvp => kvp.Key.Substring("link_".Length), kvp => (object)kvp.Value[0]);
var urlHelper = _actionContext.HttpContext.RequestServices.GetService<IUrlHelper>();
var urlHelper = _actionContext.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
link = urlHelper.Action(query["link_action"], query["link_controller"], values);
}

View File

@ -33,7 +33,7 @@ namespace VersioningWebSite
.Where(kvp => kvp.Key != "link" && kvp.Key != "link_action" && kvp.Key != "link_controller")
.ToDictionary(kvp => kvp.Key.Substring("link_".Length), kvp => (object)kvp.Value[0]);
var urlHelper = _actionContext.HttpContext.RequestServices.GetService<IUrlHelper>();
var urlHelper = _actionContext.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
link = urlHelper.Action(query["link_action"], query["link_controller"], values);
}