Пример #1
0
        public void ConfigureServices(IServiceCollection services)
        {
            var beforeCount = services.Count;

            try
            {
                // Global configurations maybe used in many places
                services.Configure <GlobalOptions>(_config);
                services.Configure <AdminOptions>(_config.GetSection("Admin"));

                // Adds a service that can resolve the client URI
                services.AddClientAppAddressResolver(_config);

                // Azure Application Insights
                string instrumentationKey = _config["APPINSIGHTS_INSTRUMENTATIONKEY"];
                if (!string.IsNullOrWhiteSpace(instrumentationKey))
                {
                    services.AddApplicationInsightsTelemetry(instrumentationKey);
                }

                // Register the API
                services.AddTellmaApi(_config)
                .AddSingleton <IServiceContextAccessor, WebServiceContextAccessor>()
                .AddClientAppProxy(_config);

                // Dependency for the GlobalController and the GlobalFilter
                services.AddScoped <GlobalSettingsProvider>();

                // Add optoinal services
                if (_opt.EmailEnabled)
                {
                    services.AddSendGrid(_config);
                }

                if (_opt.SmsEnabled)
                {
                    services.AddTwilio(_config);
                }

                if (_opt.AzureBlobStorageEnabled)
                {
                    // This overrides the SQL implementation added by default
                    services.AddAzureBlobStorage(_config);
                }

                // Add the default localization that relies on resource files in /Resources
                services.AddLocalization();

                // Register MVC
                services
                .AddControllersWithViews(opt =>
                {
                    // This filter checks version headers (e.g. x-translations-version) supplied by the client and efficiently
                    // sets a response header to 'Fresh' or 'Stale' to prompt the client to refresh its settings if necessary
                    opt.Filters.Add <GlobalFilter>();

                    // This filters traps any exception in the action execution and turns it into a proper response
                    opt.Filters.Add <ExceptionsFilter>();
                })
                .ConfigureApiBehaviorOptions(opt =>
                {
                    // Validation is performed at the business service layer, not at the Controller layer
                    // Controllers are very thin, their only purpose is to translate from web world to C# world
                    opt.SuppressModelStateInvalidFilter = true;
                })
                .AddDataAnnotationsLocalization(opt =>
                {
                    // This allows us to have a single RESX file for all classes and namespaces
                    opt.DataAnnotationLocalizerProvider = (type, factory) => factory.Create(typeof(Strings));
                })
                .AddJsonOptions(opt =>
                {
                    JsonUtil.ConfigureOptionsForWeb(opt.JsonSerializerOptions);
                });

                // Setup an embedded instance of identity server in the same domain as the API if it is enabled in the configuration
                if (_opt.EmbeddedIdentityServerEnabled)
                {
                    // To support the authentication pages
                    var mvcBuilder = services.AddRazorPages();

                    services.AddEmbeddedIdentityServer(config: _config, mvcBuilder: mvcBuilder,
                                                       isDevelopment: _env.IsDevelopment());

                    // Add services for authenticating API calls against the embedded
                    // Identity server, and helper services for accessing claims
                    services.AddApiAuthWithEmbeddedIdentity();
                }
                else
                {
                    // Add services for authenticating API calls against an external
                    // OIDC authority, and helper services for accessing claims
                    services.AddApiAuthWithExternalIdentity(_config);
                }

                // Configure some custom behavior for API controllers
                services.Configure <ApiBehaviorOptions>(opt =>
                {
                    // This overrides the default behavior, when there are validation
                    // errors we return a 422 unprocessable entity, instead of the default
                    // 400 bad request, this makes it easier for clients to distinguish
                    // such kinds of errors and handle them in a special way, for example:
                    // by showing them on the relevant fields with a red highlight
                    opt.InvalidModelStateResponseFactory = ctx => new UnprocessableEntityObjectResult(ctx.ModelState);
                });

                // Embedded Client Application
                if (_opt.EmbeddedClientApplicationEnabled)
                {
                    services.AddSpaStaticFiles(opt =>
                    {
                        // In production, the Angular files will be served from this directory
                        opt.RootPath = "ClientApp/dist";
                    });
                }

                // Giving access to clients that are hosted on another domain
                services.AddCors();

                // This is a required configuration since ASP.NET Core 2.1
                services.AddHttpsRedirection(opt =>
                {
                    opt.HttpsPort = 443;
                });

                // Adds and configures SignalR
                services.AddSignalRImplementation(_config, _env);

                // API Versioning
                services.AddApiVersioning(options =>
                {
                    options.DefaultApiVersion = new ApiVersion(1, 0);
                    options.AssumeDefaultVersionWhenUnspecified = true;
                    options.ReportApiVersions = true;
                    options.ApiVersionReader  = new HeaderApiVersionReader("X-Api-Version");
                });
            }
            catch (Exception ex)
            {
                // Remove all custom services to avoid a DI validation exception
                while (services.Count > beforeCount)
                {
                    services.RemoveAt(beforeCount);
                }

                // The configuration encountered a fatal error, usually a required yet
                // missing configuration. Setting this property instructs the middleware
                // to short-circuit and just return this error in plain text
                SetStartupError(ex);
            }
        }