配置 Core 1.0 以面向 net45 和 运行 IIS Express

Configuring Core 1.0 to target net45 and run IIS Express

我希望能帮助我使用最新的 ASPNET Core 1.0 工具正确配置我的 MVC 应用程序以面向 .NET 4.5。

从 Microsoft.AspNet.Mvc 6 RC 升级到 Microsoft.AspNetCore.Mvc 1.0.0.

后,除了 IISExpress 的 502.3 响应外,我无法得到任何其他信息

我猜我在这里遗漏了一些基本配置,但是关于使用核心工具定位 .NET 4.5 的文档非常少。

感谢帮助,提前致谢。

这是我的 project.json:

{
"buildOptions": {
    "emitEntryPoint": true,
    "compile": {
        "exclude": [
            "wwwroot",
            "node_modules"
        ]
    }
},
"configurations": {
    "Development": {}
},
"dependencies": {
    "Autofac": "4.0.0-rc1-177",
    "Autofac.Extensions.DependencyInjection": "4.0.0-rc1-177",
    "AutofacSerilogIntegration": "1.0.12",
    "AutoMapper": "4.2.1",
    "MediaTypeMap": "2.1.0",
    "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0",
    "Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0",
    "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.0.0",
    "Microsoft.AspNetCore.Diagnostics": "1.0.0",
    "Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.0.0",
    "Microsoft.AspNetCore.Http.Abstractions": "1.0.0",
    "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0",
    "Microsoft.AspNetCore.Mvc": "1.0.0",
    "Microsoft.AspNetCore.Mvc.TagHelpers": "1.0.0",
    "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
    "Microsoft.AspNetCore.StaticFiles": "1.0.0",
    "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
    "Microsoft.Extensions.Configuration.FileProviderExtensions": "1.0.0-rc1-final",
    "Microsoft.Extensions.Configuration.Json": "1.0.0",
    "Microsoft.Extensions.Configuration.UserSecrets": "1.0.0-rc1-final",
    "Microsoft.Extensions.DependencyInjection": "1.0.0",
    "Microsoft.Extensions.Logging.Abstractions": "1.0.0",
    "Microsoft.Extensions.Logging.Console": "1.0.0",
    "Microsoft.Extensions.Logging.Debug": "1.0.0",
    "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-rc2-final",
    "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": "1.0.0-preview2-final",
    "Serilog.Extensions.Logging": "1.0.0",
    "Serilog.Sinks.RollingFile": "2.1.0",
    "Swashbuckle.SwaggerGen": "6.0.0-beta901",
    "Swashbuckle.SwaggerUi": "6.0.0-beta901"
},
"frameworks": {
    "net451": {}
},
"publishOptions": {
    "exclude": [
        "**.user",
        "**.vspscc"
    ],
    "include": [
        "Areas",
        "Views",
        "wwwroot",
        "appsettings.json",
        "web.config"
    ]
},
"scripts": {
    "prepublish": [ "npm install", "bower install", "gulp" ]
},

"tools": {
    "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-*",
    "Microsoft.Extensions.SecretManager.Tools": "1.0.0-preview2-final"
},
"userSecretsId": "asdf",
"version": "1.0.0-*",
"webroot": "wwwroot"

}

这是我的主要内容:

public static void Main(string[] args) {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();
        host.Run();
    }

Startup.cs:

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using AutofacSerilogIntegration;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Converters;
using Serilog;
using Swashbuckle.Swagger.Model;

namespace Web
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var contentRootPath = env.ContentRootPath;
            // Set up configuration sources.
            var builder = new ConfigurationBuilder()
                .SetBasePath(contentRootPath)
                .AddEnvironmentVariables()
                .AddJsonFile("appsettings.json")
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", true);


        builder.AddEnvironmentVariables();
        Configuration = builder.Build();

        if (env.IsDevelopment())
        {
            // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
            builder.AddUserSecrets();
        }

        builder.AddEnvironmentVariables();
        Configuration = builder.Build();
        GlobalVariables.WebRootPath = env.WebRootPath;

        var configSettings = new ConfigSettings(Configuration);
        string logPath = configSettings.LoggingConfiguration.Path;
        logPath = LoggingPathHelper.GetPath(logPath, env.WebRootPath);

        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Information()
            .WriteTo.RollingFile(logPath)
            .CreateLogger();
    }

    public IConfigurationRoot Configuration { get; set; }


    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory,
        IApplicationLifetime appLifetime)
    {
        Serilog.SerilogLoggerFactoryExtensions.AddSerilog(loggerFactory);
        appLifetime?.ApplicationStopped.Register(Log.CloseAndFlush);
        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

        if (env.IsDevelopment())
        {
            app.UseBrowserLink();
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");

            // For more details on creating database during deployment see http://go.microsoft.com/fwlink/?LinkID=615859
            //CORE 1.0 upgrade: this doesn't appear to be used. Appears to be redundant to the work done in Identity project - asteffes
            //try {
            //    using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
            //        .CreateScope()) {
            //        serviceScope.ServiceProvider.GetService<ApplicationDbContext>()
            //            .Database.Migrate();
            //    }
            //}
            //catch {
            //}
        }

        app.UseStaticFiles();


        // Tell OWIN to use Cookies to save the Identity and other Claims information
        var cookieAuthenticationOptions = new CookieAuthenticationOptions
        {
            AuthenticationScheme = "Cookies",
            AutomaticAuthenticate = true
        };
        app.UseCookieAuthentication(cookieAuthenticationOptions);

        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap = new Dictionary<string, string>();
        var options = new JwtBearerOptions
        {
            Authority = GlobalVariables.Settings.SecurityIdentityServerEndpointURI,
            RequireHttpsMetadata = false,
            Audience = GlobalVariables.Settings.SecurityIdentityServerEndpointURI + "resources",
            AutomaticAuthenticate = true
        };




        app.UseMvc(routes =>
        {
            routes.MapRoute(
                "areaRoute",
                "{area:exists}/{controller}/{action}");

            routes.MapRoute(
                "default",
                "{controller=App}/{action=Index}/{id?}");
        });

        // Add Swagger support
        // https://damienbod.com/2015/12/13/asp-net-5-mvc-6-api-documentation-using-swagger/


        app.UseSwaggerUi();
    }

    // This method gets called by the runtime. Use this method to add services to the container.
    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        var exceptionNotifierFilter = new ExceptionNotifierFilter();
        services.AddMvc(options => { options.Filters.Add(exceptionNotifierFilter); })
            // Make all results be camel-case
            .AddJsonOptions(options =>
            {
                options.SerializerSettings.ContractResolver =
                    new CustomCamelCasePropertyNamesContractResolver();
                options.SerializerSettings.Converters.Add(
                    new StringEnumConverter {CamelCaseText = true});
            });


        // Add Swagger support
        services.AddSwaggerGen();
        // https://damienbod.com/2015/12/13/asp-net-5-mvc-6-api-documentation-using-swagger/
        var pathToDoc = Configuration["Swagger:Path"];
        services.AddSwaggerGen();
        services.ConfigureSwaggerGen(options =>
        {
            var info = new Info
            {
                Version = "v1",
                Title = "API",
                Description = "API",
            };
            options.SingleApiVersion(info);
            options.IncludeXmlComments(pathToDoc);
            var addFileUploadParams = new AddFileUploadParams();
            options.OperationFilter<AddFileUploadParams>(addFileUploadParams);
            options.DescribeAllEnumsAsStrings();
            //options.OperationFilter(new Swashbuckle.SwaggerGen.XmlComments.ApplyXmlActionComments(pathToDoc));
        });

        services.AddTransient<IEmailSender, AuthMessageSender>();
        services.AddTransient<ISmsSender, AuthMessageSender>();

        var autofacContainer = RegisterAutofac(services, Configuration);
        var serviceProvider = autofacContainer.Resolve<IServiceProvider>();

        // Save the ConfigSetttings instance in the Service Provider so it can be used elsewhere in the application.
        // This is necessary because serviceProvider is no longer accessible from within the application.
        GlobalVariables.Settings = serviceProvider.GetService<ConfigSettings>();
        GlobalVariables.AutofacContainer = autofacContainer;
        GlobalServiceVariables.AutofacContainer = autofacContainer;

        InjectDependenciesInto(exceptionNotifierFilter, serviceProvider);

        // Return the ServiceProvider created above based on AutofacModule
        // NOTE:  This changes the return value of Configuration to IServiceProvider
        return serviceProvider;
    }


    private static void InjectDependenciesInto(ExceptionNotifierFilter exceptionNotifierFilter,
        IServiceProvider serviceProvider)
    {
        // Have to use setter injection since the instance had to be created earlier
        exceptionNotifierFilter.EmailService = serviceProvider.GetService<IEmailsService>();
        exceptionNotifierFilter.ConfigSettings = serviceProvider.GetService<ConfigSettings>();
        exceptionNotifierFilter.UserResolver = serviceProvider.GetService<IUserResolver>();
        exceptionNotifierFilter.ExceptionLogEntryRepository =
            serviceProvider.GetService<IEntityRepository<ExceptionLogEntry>>();
        exceptionNotifierFilter.CryptographyService = serviceProvider.GetService<ICryptographyService>();
    }

    private static IContainer RegisterAutofac(IServiceCollection services, IConfigurationRoot configuration)
    {
        var builder = new ContainerBuilder();

        // We need to pass in the web assembly and the IServiceFacade so that Autofac can register them;
        // since web has a dependency on init, init cannot have a direct dependency back to web.
        var maxAutofacModule = new MaxAutofacModule(configuration);
        maxAutofacModule.IncludeServiceFacadeRegistrations(typeof(Startup).Assembly, typeof(IServiceFacade));
        builder.RegisterModule(maxAutofacModule);
        builder.Populate(services);

        var container = builder.Build();

        builder.RegisterLogger(Log.Logger);
        return container;
    }
}

}

我错过了什么?

  1. .UseContentRoot(Directory.GetCurrentDirectory())添加到Program.cs,在.UseKestrel().UseIISIntegration()之间

  2. 检查项目的 web.config 根目录(不是 wwwroot!),它必须看起来 like this