Updated to .net core 3.0

This commit is contained in:
tidusjar 2019-11-05 22:04:37 +00:00
parent b07833e0e8
commit 379ffeddba
13 changed files with 66 additions and 163 deletions

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework> <TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View file

@ -120,8 +120,8 @@ namespace Ombi.DependencyInjection
public static void RegisterApi(this IServiceCollection services) public static void RegisterApi(this IServiceCollection services)
{ {
services.AddSingleton<IApi, Api.Api>(); services.AddScoped<IApi, Api.Api>();
services.AddSingleton<IOmbiHttpClient, OmbiHttpClient>(); // https://blogs.msdn.microsoft.com/alazarev/2017/12/29/disposable-finalizers-and-httpclient/ services.AddScoped<IOmbiHttpClient, OmbiHttpClient>(); // https://blogs.msdn.microsoft.com/alazarev/2017/12/29/disposable-finalizers-and-httpclient/
services.AddTransient<IMovieDbApi, Api.TheMovieDb.TheMovieDbApi>(); services.AddTransient<IMovieDbApi, Api.TheMovieDb.TheMovieDbApi>();
services.AddTransient<IPlexApi, PlexApi>(); services.AddTransient<IPlexApi, PlexApi>();
services.AddTransient<IEmbyApi, EmbyApi>(); services.AddTransient<IEmbyApi, EmbyApi>();

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework> <TargetFramework>netcoreapp3.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework> <TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework> <TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View file

@ -39,11 +39,11 @@ namespace Ombi.Schedule
// .Build(); // .Build();
//} //}
public static async Task UseQuartz(this IApplicationBuilder app) public static async Task UseQuartz(this IServiceProvider app)
{ {
// Job Factory through IOC container // Job Factory through IOC container
var jobFactory = (IJobFactory)app.ApplicationServices.GetService(typeof(IJobFactory)); var jobFactory = (IJobFactory)app.GetService(typeof(IJobFactory));
var service = (ISettingsService<JobSettings>)app.ApplicationServices.GetService(typeof(ISettingsService<JobSettings>)); var service = (ISettingsService<JobSettings>)app.GetService(typeof(ISettingsService<JobSettings>));
var s = service.GetSettings(); var s = service.GetSettings();
// Set job factory // Set job factory
OmbiQuartz.Instance.UseJobFactory(jobFactory); OmbiQuartz.Instance.UseJobFactory(jobFactory);

View file

@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup><TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>netcoreapp2.2</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework> <TargetFramework>netcoreapp3.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>

View file

@ -1,6 +1,6 @@
<Project ToolsVersion="15.0" Sdk="Microsoft.NET.Sdk.Web"> <Project ToolsVersion="15.0" Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework> <TargetFramework>netcoreapp3.0</TargetFramework>
<RuntimeIdentifiers>win10-x64;win10-x86;osx-x64;linux-x64;linux-arm;linux-arm64;</RuntimeIdentifiers> <RuntimeIdentifiers>win10-x64;win10-x86;osx-x64;linux-x64;linux-arm;linux-arm64;</RuntimeIdentifiers>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion> <TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
@ -58,14 +58,8 @@
<PackageReference Include="AutoMapper" Version="6.1.1" /> <PackageReference Include="AutoMapper" Version="6.1.1" />
<PackageReference Include="CommandLineParser" Version="2.4.3" /> <PackageReference Include="CommandLineParser" Version="2.4.3" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.1" /> <PackageReference Include="Hangfire.AspNetCore" Version="1.7.1" />
<PackageReference Include="Hangfire.Console" Version="1.4.2" />
<PackageReference Include="Hangfire.MemoryStorage.Core" Version="1.4.0" />
<PackageReference Include="Hangfire.RecurringJobExtensions" Version="1.1.6" />
<PackageReference Include="Hangfire.SQLite" Version="1.4.2" /> <PackageReference Include="Hangfire.SQLite" Version="1.4.2" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Api.Analyzers" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="2.2.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.2.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.2.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="2.2.0" /> <PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="2.2.0" />
@ -75,8 +69,11 @@
<PackageReference Include="Serilog.Sinks.File" Version="4.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />
<PackageReference Include="Serilog.Sinks.RollingFile" Version="3.3.1-dev-00771" /> <PackageReference Include="Serilog.Sinks.RollingFile" Version="3.3.1-dev-00771" />
<PackageReference Include="Serilog.Sinks.SQLite" Version="4.0.0" /> <PackageReference Include="Serilog.Sinks.SQLite" Version="4.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="4.0.1" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0-rc4" />
<PackageReference Include="System.Security.Cryptography.Csp" Version="4.3.0" /> <PackageReference Include="System.Security.Cryptography.Csp" Version="4.3.0" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="3.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="3.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -9,6 +9,7 @@ using CommandLine;
using CommandLine.Text; using CommandLine.Text;
using Microsoft.AspNetCore; using Microsoft.AspNetCore;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using Ombi.Helpers; using Ombi.Helpers;
namespace Ombi namespace Ombi
@ -115,7 +116,7 @@ namespace Ombi
Console.WriteLine($"We are running on {urlValue}"); Console.WriteLine($"We are running on {urlValue}");
CreateWebHostBuilder(args).Build().Run(); CreateHostBuilder(args).Build().Run();
} }
private static void DeleteSchedules() private static void DeleteSchedules()
@ -283,11 +284,18 @@ namespace Ombi
} }
} }
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => public static IHostBuilder CreateHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args) Host.CreateDefaultBuilder(args)
.UseStartup<Startup>() .ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel(serverOptions =>
{
// Set properties and call methods on options
});
webBuilder.PreferHostingUrls(true)
.UseUrls(UrlArgs) .UseUrls(UrlArgs)
.PreferHostingUrls(true); .UseStartup<Startup>();
});
private static string HelpOutput(ParserResult<Options> args) private static string HelpOutput(ParserResult<Options> args)
{ {

View file

@ -3,21 +3,17 @@ using AutoMapper.EquivalencyExpression;
using Hangfire; using Hangfire;
using Hangfire.Dashboard; using Hangfire.Dashboard;
using Hangfire.MemoryStorage; using Hangfire.MemoryStorage;
using Hangfire.SQLite;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SpaServices;
using Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer;
using Microsoft.AspNetCore.StaticFiles; using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Settings; using Ombi.Core.Settings;
using Ombi.DependencyInjection; using Ombi.DependencyInjection;
@ -33,6 +29,8 @@ using Serilog;
using SQLitePCL; using SQLitePCL;
using System; using System;
using System.IO; using System.IO;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using ILogger = Serilog.ILogger; using ILogger = Serilog.ILogger;
namespace Ombi namespace Ombi
@ -41,7 +39,7 @@ namespace Ombi
{ {
public static StoragePathSingleton StoragePath => StoragePathSingleton.Instance; public static StoragePathSingleton StoragePath => StoragePathSingleton.Instance;
public Startup(IHostingEnvironment env) public Startup(IWebHostEnvironment env)
{ {
Console.WriteLine(env.ContentRootPath); Console.WriteLine(env.ContentRootPath);
var builder = new ConfigurationBuilder() var builder = new ConfigurationBuilder()
@ -62,7 +60,7 @@ namespace Ombi
public IConfigurationRoot Configuration { get; } public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container. // This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddIdentity<OmbiUser, IdentityRole>() services.AddIdentity<OmbiUser, IdentityRole>()
.AddEntityFrameworkStores<OmbiContext>() .AddEntityFrameworkStores<OmbiContext>()
@ -86,8 +84,7 @@ namespace Ombi
services.AddJwtAuthentication(Configuration); services.AddJwtAuthentication(Configuration);
services.AddMvc() services.AddMvc()
.AddJsonOptions(x => .AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
services.AddOmbiMappingProfile(); services.AddOmbiMappingProfile();
services.AddAutoMapper(expression => { expression.AddCollectionMappers(); }); services.AddAutoMapper(expression => { expression.AddCollectionMappers(); });
@ -99,7 +96,9 @@ namespace Ombi
services.AddHangfire(x => services.AddHangfire(x =>
{ {
x.UseMemoryStorage(); x.UseMemoryStorage();
#pragma warning disable ASP0000 // Do not call 'IServiceCollection.BuildServiceProvider' in 'ConfigureServices'
x.UseActivator(new IoCJobActivator(services.BuildServiceProvider())); x.UseActivator(new IoCJobActivator(services.BuildServiceProvider()));
#pragma warning restore ASP0000 // Do not call 'IServiceCollection.BuildServiceProvider' in 'ConfigureServices'
}); });
SQLitePCL.raw.sqlite3_config(raw.SQLITE_CONFIG_MULTITHREAD); SQLitePCL.raw.sqlite3_config(raw.SQLITE_CONFIG_MULTITHREAD);
@ -112,38 +111,32 @@ namespace Ombi
.AllowCredentials(); .AllowCredentials();
})); }));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Latest);
services.AddSignalR(); services.AddSignalR();
services.AddSpaStaticFiles(configuration => services.AddSpaStaticFiles(configuration =>
{ {
configuration.RootPath = "ClientApp/dist"; configuration.RootPath = "ClientApp/dist";
}); });
// Build the intermediate service provider
return services.BuildServiceProvider();
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // 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, public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
IMemoryCache cache, IServiceProvider serviceProvider)
{ {
app.UseForwardedHeaders(new ForwardedHeadersOptions app.UseForwardedHeaders(new ForwardedHeadersOptions
{ {
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
}); });
app.UseQuartz().GetAwaiter().GetResult(); serviceProvider.UseQuartz().GetAwaiter().GetResult();
var ctx = serviceProvider.GetService<IOmbiContext>(); var ctx = serviceProvider.GetService<IOmbiContext>();
loggerFactory.AddSerilog(); loggerFactory.AddSerilog();
app.UseHealthChecks("/health");
app.UseSpaStaticFiles(); app.UseSpaStaticFiles();
var ombiService = var ombiService =
app.ApplicationServices.GetService<ISettingsService<OmbiSettings>>(); serviceProvider.GetService<ISettingsService<OmbiSettings>>();
var settings = ombiService.GetSettings(); var settings = ombiService.GetSettings();
if (settings.ApiKey.IsNullOrEmpty()) if (settings.ApiKey.IsNullOrEmpty())
{ {
@ -180,20 +173,7 @@ namespace Ombi
app.UseHangfireServer(new BackgroundJobServerOptions app.UseHangfireServer(new BackgroundJobServerOptions
{WorkerCount = 1, ServerTimeout = TimeSpan.FromDays(1), ShutdownTimeout = TimeSpan.FromDays(1)}); {WorkerCount = 1, ServerTimeout = TimeSpan.FromDays(1), ShutdownTimeout = TimeSpan.FromDays(1)});
if (env.IsDevelopment())
{
app.UseHangfireDashboard(settings.BaseUrl.HasValue() ? $"{settings.BaseUrl}/hangfire" : "/hangfire",
new DashboardOptions
{
Authorization = new[] {new HangfireAuthorizationFilter()}
});
}
GlobalJobFilters.Filters.Add(new AutomaticRetryAttribute {Attempts = 3});
// Setup the scheduler
//var jobSetup = app.ApplicationServices.GetService<IJobSetup>();
//jobSetup.Setup();
ctx.Seed(); ctx.Seed();
var settingsctx = serviceProvider.GetService<ISettingsContext>(); var settingsctx = serviceProvider.GetService<ISettingsContext>();
var externalctx = serviceProvider.GetService<IExternalContext>(); var externalctx = serviceProvider.GetService<IExternalContext>();
@ -207,7 +187,10 @@ namespace Ombi
ContentTypeProvider = provider, ContentTypeProvider = provider,
}); });
app.UseRouting();
app.UseAuthentication(); app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<ErrorHandlingMiddleware>(); app.UseMiddleware<ErrorHandlingMiddleware>();
app.UseMiddleware<ApiKeyMiddlewear>(); app.UseMiddleware<ApiKeyMiddlewear>();
@ -226,9 +209,12 @@ namespace Ombi
} }
}); });
app.UseSignalR(routes => { routes.MapHub<NotificationHub>("/hubs/notification"); }); app.UseEndpoints(endpoints =>
{
app.UseMvcWithDefaultRoute(); endpoints.MapControllers();
endpoints.MapHub<NotificationHub>("/hubs/notification");
endpoints.MapHealthChecks("/health");
});
app.UseSpa(spa => app.UseSpa(spa =>
{ {
@ -240,24 +226,5 @@ namespace Ombi
}); });
} }
private static bool IsSpaRoute(HttpContext context)
{
var path = context.Request.Path;
// This should probably be a compiled regex
return path.StartsWithSegments("/static")
|| path.StartsWithSegments("/sockjs-node")
|| path.StartsWithSegments("/socket.io")
|| path.ToString().Contains(".hot-update.");
}
public class HangfireAuthorizationFilter : IDashboardAuthorizationFilter
{
public bool Authorize(DashboardContext context)
{
return true;
}
}
} }
} }

View file

@ -5,11 +5,13 @@ using System.Reflection;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.JsonPatch.Operations;
using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Ombi.Config; using Ombi.Config;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Models.Identity; using Ombi.Models.Identity;
@ -18,65 +20,34 @@ using Swashbuckle.AspNetCore.SwaggerGen;
namespace Ombi namespace Ombi
{ {
public class AddRequiredHeaderParameter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
if (operation.Parameters == null)
operation.Parameters = new List<IParameter>();
operation.Parameters.Add(new NonBodyParameter
{
Name = "ApiKey",
In = "header",
Type = "apiKey",
});
}
}
public static class StartupExtensions public static class StartupExtensions
{ {
public static void AddSwagger(this IServiceCollection services) public static void AddSwagger(this IServiceCollection services)
{ {
services.AddSwaggerGen(c => services.AddSwaggerGen(c =>
{ {
c.DescribeAllEnumsAsStrings(); c.SwaggerDoc("v1", new OpenApiInfo()
c.SwaggerDoc("v1", new Info
{ {
Version = "v1", Version = "v1",
Title = "Ombi Api V1", Title = "Ombi Api V1",
Contact = new Contact Contact = new OpenApiContact
{ {
Name = "Jamie Rees", Name = "Jamie Rees",
Url = "https://www.ombi.io/" Url = new Uri("https://www.ombi.io/")
} }
}); });
var security = new Dictionary<string, IEnumerable<string>>
{
//{"Bearer", new string[] { }},
{"ApiKey", new string[] { }},
};
//c.AddSecurityDefinition("Bearer", new ApiKeyScheme
//{
// Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
// Name = "Authorization",
// In = "header",
// Type = "apiKey"
//});
c.AddSecurityDefinition("ApiKey", new ApiKeyScheme
c.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme
{ {
Description = "API Key provided by Ombi. Example: \"ApiKey: {token}\"", Description = "API Key provided by Ombi. Example: \"ApiKey: {token}\"",
Name = "ApiKey", Name = "ApiKey",
In = "header", In = ParameterLocation.Header,
Type = "apiKey" Type = SecuritySchemeType.ApiKey
}); });
c.AddSecurityRequirement(security);
c.CustomSchemaIds(x => x.FullName); c.CustomSchemaIds(x => x.FullName);
c.OperationFilter<AddRequiredHeaderParameter>();
var basePath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); var basePath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
var xmlPath = Path.Combine(basePath, "Swagger.xml"); var xmlPath = Path.Combine(basePath, "Swagger.xml");
try try
@ -89,22 +60,11 @@ namespace Ombi
} }
c.OperationFilter<SwaggerOperationFilter>();
c.DescribeAllParametersInCamelCase(); c.DescribeAllParametersInCamelCase();
}); });
} }
public class JwtBearer : SecurityScheme
{
public string Name { get; set; }
public string In { get; set; }
public JwtBearer()
{
this.Type = "bearer";
}
}
public static void AddAppSettingsValues(this IServiceCollection services, IConfigurationRoot configuration) public static void AddAppSettingsValues(this IServiceCollection services, IConfigurationRoot configuration)
{ {

View file

@ -1,28 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Authorization;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Ombi
{
public class SwaggerOperationFilter : IOperationFilter
{
public string Name { get; private set; }
public SwaggerOperationFilter()
{
Name = "Authorization";
}
public void Apply(Operation operation, OperationFilterContext context)
{
if (operation.Parameters == null)
operation.Parameters = new List<IParameter>();
var tokenAuthDict = new Dictionary<string, IEnumerable<string>> {{Name, new List<string>()}};
operation.Security = new IDictionary<string, IEnumerable<string>>[] { tokenAuthDict };
}
}
}