weixin_39645165
weixin_39645165
2021-01-05 01:54

ConfigureHostDefaults

Hello,

I am wondering if you have ConfigureHostDefaults for a Worker Service like you have ConfigureWebHostDefaults for a ASP.Net Core Web Application?

You can use ConifugreWebHostDefaults together with UseStartup in a WorkerService but then your service starts to listen at the default ports...


public static void Run(string[] args)
{
    using (IHost host = Host.CreateDefaultBuilder(args)
            .UseContentRoot(Directory.GetCurrentDirectory())
            .ConfigureWebHostDefaults(webBuilder => webBuilder
            .UseStartup<tstartup>())
            .Build())
    {
        host.Run();
    }
}
</tstartup>

该提问来源于开源项目:dotnet/extensions

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

13条回答

  • weixin_39729837 weixin_39729837 4月前

    Startup was debated during the 3.0 milestone but we decided to leave it for web scenarios only since Configure didn't really make any sense (because of what mentioned). I'd file an issue on https://github.com/aspnet/Extensions for further discussion so we can flesh something out for the next major release.

    点赞 评论 复制链接分享
  • weixin_39645165 weixin_39645165 4月前

    I made a quick fix that works for me at this moment, every Method in IHostBuilder that contains any kind of Action in it can be used in my Build file. For example: IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate);

    it's just an idea of how i implemented it at the moment, but it gives me the possibility to have an over-writable class:

    The base implementation

    The replacement for the Startup.cs, i called it BuildHost.cs for the moment, because i don't have a good name yet.

    
    public class BuildHost
    {
        public virtual void ConfigureAppConfiguration(HostBuilderContext hostBuilderContext, IConfigurationBuilder configurationBuilder)
        {
            configurationBuilder.AddConfiguration(hostBuilderContext.HostingEnvironment.EnvironmentName);
        }
    
        public virtual void ConfigureServices(HostBuilderContext hostBuilderContext, IServiceCollection serviceCollection)
        {
            serviceCollection.AddConfiguration();
        }
    }
    

    This is the ProgramService.cs

    
    public class ProgramService<tbuild>
        where TBuild : BuildService, new()
    {
        public static void Run(string[] args)
        {
            using (IHost host = Host.CreateDefaultBuilder(args)
                .UseContentRoot(Directory.GetCurrentDirectory())
                .Build<tbuild>()
                .Build())
            {
                host.Run();
            }
        }
    }
    </tbuild></tbuild>

    The service that derive the base implementation

    Program.cs

    
    public class Program : ProgramService<build>
    {
        public static void Main(string[] args)
        {
            Run(args);
        }
    }
    </build>

    Build.cs

    
    public class Build : BuildService
    {
        public override void ConfigureServices(HostBuilderContext hostBuilderContext, IServiceCollection serviceCollection)
        {
            base.ConfigureServices(hostBuilderContext, serviceCollection);
    
            // At least 1 call to this type is required else will the assembly be excluded out of the references
            serviceCollection
                .AddHostedServices(typeof(RoutinesWorker).Assembly)
                .AddRoutines();
        }
    }
    

    The Build extension

    
    public static class HostBuilderExtensions
    {
        public static IHostBuilder Build<tbuild>(this IHostBuilder hostBuilder)
            where TBuild : class, new()
        {
            TBuild startup = Activator.CreateInstance<tbuild>();
    
            foreach (MethodInfo hostBuilderMethodInfo in hostBuilder.GetType().GetMethods())
            {
                MethodInfo startupMethodInfo = typeof(TBuild).GetMethod(hostBuilderMethodInfo);
                hostBuilder.CallMethod(startup, hostBuilderMethodInfo, startupMethodInfo);
            }
    
            return hostBuilder;
        }
    
        private static void CallMethod<tbuild>(this IHostBuilder hostBuilder, TBuild startup, MethodInfo hostBuilderMethodInfo, MethodInfo startupMethodInfo)
            where TBuild : class, new()
        {
            if (startupMethodInfo != null)
            {
                Delegate  = startupMethodInfo.CreateDelegate(hostBuilderMethodInfo.GetParameters()[0].ParameterType, startup);
                hostBuilderMethodInfo.Invoke(hostBuilder, new object[] {  });
            }
        }
    
        private static MethodInfo GetMethod(this Type startupType, MethodInfo methodInfo)
        {
            ParameterInfo[] parameterInfos = methodInfo.GetParameters();
    
            if (parameterInfos?.Length == 1 &&
                parameterInfos[0].ParameterType.IsGenericType &&
                parameterInfos[0].ParameterType.IsActionType())
            {
                Type[] types = parameterInfos[0].ParameterType.GetGenericArguments();
                return startupType.GetMethod(methodInfo.Name, types);
            }
    
            return null;
        }
    
        private static bool IsActionType(this Type type)
        {
            string typeName = $"System.Action`{type.GetGenericArguments().Length}";
            Type actionType = typeof(Action).Assembly.GetType(typeName);
    
            return type.GetGenericTypeDefinition() == actionType;
        }
    }
    </tbuild></tbuild></tbuild>

    This is not what the .UseStartup does, but for the moment it is a simple work around while i hope you want to add something similar as UseStartup or some other nice extension that can be used for it as well in the next Major Release.

    点赞 评论 复制链接分享
  • weixin_39560029 weixin_39560029 4月前

    To clarify, the request seems to have changed quite a bit here. You're no longer looking for support for Startup in generic host, but instead for the ability to specify a type which can contain any number of the Configure methods hanging off HostBuilder? That seems like a weird inversion to build in, especially when anyone can attach a Configure method via extension methods, it's not a fixed set.

    点赞 评论 复制链接分享
  • weixin_39645165 weixin_39645165 4月前

    My request is actually to have a startup.cs possibility when want to start a service. It's only called when we run a Web Application.

    The extra request/option i pass is that you give the possibility to call all extension methods you have in the separated startup.cs. I suggest this because you can keep an equal operation that you already used before for Web Applications in previous .Net Core versions. Now you can use the startup.cs and the extension methods you created for .Net Core 3.0.

    I hope this makes it more clear what i'm suggesting?

    点赞 评论 复制链接分享
  • weixin_39611275 weixin_39611275 4月前

    As part of the migration of components from dotnet/extensions to dotnet/runtime (https://github.com/aspnet/Announcements/issues/411) we will be bulk closing some of the older issues. If you are still interested in having this issue addressed, just comment and the issue will be automatically reactivated (even if you aren't the author). When you do that, I'll page the team to come take a look. If you've moved on or workaround the issue and no longer need this change, just ignore this and the issue will be closed in 7 days.

    If you know that the issue affects a package that has moved to a different repo, please consider re-opening the issue in that repo. If you're unsure, that's OK, someone from the team can help!

    点赞 评论 复制链接分享
  • weixin_39996141 weixin_39996141 4月前

    Do this in your WorkerService project => Edit the .csproj file and add this

    <ItemGroup>
        <FrameworkReference Include="Microsoft.AspNetCore.App" />
    </ItemGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
        <PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.7" />
    </ItemGroup>
    

    Then you should have access to ConfigureWebHostDefaults()

    点赞 评论 复制链接分享
  • weixin_39611275 weixin_39611275 4月前

    Paging /extensions-migration ! This issue has been revived from staleness. Please take a look and route to the appropriate repository.

    点赞 评论 复制链接分享
  • weixin_39528843 weixin_39528843 4月前

    What defaults are you trying to get? Host.CreateDefaultBuilder provides the defaults for non-web apps.

    点赞 评论 复制链接分享
  • weixin_39645165 weixin_39645165 4月前

    I have a framework where the core of my webapplications is in, and for webapplications i call the run with a generic startup class. In that startup class i do my default configuration and injection and if i want extra i just make a startup file deriving from my base startup file and add my extra injection.

    I understand that you call ConfigureWebHostDefaults, but i would do it like this:

    
    public static void Run(string[] args)
    {
        using (IHost host = Host.CreateDefaultBuilder(args)
                .UseContentRoot(Directory.GetCurrentDirectory())
                .ConfigureWebHostDefaults()
                .UseStartup<tstartup>()
                .Build())
        {
            host.Run();
        }
    }
    </tstartup>

    In this case you can use the magic startup file as in webapplications as in worker services. The Program.cs should not do more in my opinion than creating the Host and Run it, how the Host is configured should be in the startup file as it is for webapplications.

    Also now you cannot use this kind of startups in a worker service: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-2.2

    And probably there are other reasons that i haven't mentioned yet that other people think about.

    Does this makes it clear why i miss the .UseStartup in Worker Services?

    点赞 评论 复制链接分享
  • weixin_39528843 weixin_39528843 4月前

    Startup is Web app specific due to Configure(IApplicationBuilder).

    点赞 评论 复制链接分享
  • weixin_39645165 weixin_39645165 4月前

    You do not only use your Startup in Web app due to Configure(IApplicationBuilder) Than you can remove the Startup from Web app as well and make an extension method ConfigureApplicationBuilder()

    Everything is there, it all works, the only problem i have is that my Worker Service starts listening at default urls, even when i do not have launchsettings or anything web related configured, it starts listening because of the ConfigureWebHostDefaults and the only difference with the IHostBuilder is that it has some extra extension methods and it has UseStartup.

    I do this: Program.cs

    
    public static void Run(string[] args)
    {
        using (IHost host = Host.CreateDefaultBuilder(args)
                .UseContentRoot(Directory.GetCurrentDirectory())
                .ConfigureWebHostDefaults(webBuilder => webBuilder
                .UseStartup<tstartup>())
                .Build())
        {
            host.Run();
        }
    }
    </tstartup>

    and Startup.cs

    
    public virtual void ConfigureServices(IServiceCollection serviceCollection)
    {
        serviceCollection
            .AddConfiguration()
            .AddHostedServices();
    }
    
    public virtual void Configure(IApplicationBuilder applicationBuilder, IHostEnvironment environment)
    {
    }
    

    And it works. So if i can just leave the Configure(IApplicationBuilder) and i do not start automatically to listen without asking for it to default localhosts my problem would be solved and we have an IHost that can always call UseStartup.

    点赞 评论 复制链接分享
  • weixin_39528843 weixin_39528843 4月前

    ConfigureWebHostDefaults brings in quite a bit of web infrastructure. We moved anything generic over to CreateDefaultBuilder and don't plan to move anything else, including Startup.

    Startup.ConfigureServices is just a wrapper for IHostBuilder.ConfigureServices now. If you like that pattern then I suggest making your own IHostBuilder.UseServices<T> extension method that only supports ConfigureServices and not Configure.

    点赞 评论 复制链接分享
  • weixin_39645165 weixin_39645165 4月前

    It's sad you won't move it again, because you could use this kind of pattern in Worker Services but also maybe there is a possibility to use this kind of pattern in Xamarin apps. My opinion is that this kind of flow really could be used in more than Web Applications. It's more than only Configuring Services, and it can be a lot more, and it can be a base class as well.

    Can there be a poll created for it? To see what other people think about it?

    Until then i will create my own UseStartup functionality. I just thought it would be useful to have, and i hoped it already existed... :D

    点赞 评论 复制链接分享