Changed EF core to normal for .net compability, changed folder structure, added test generation

This commit is contained in:
Jan Zubrycki 2020-06-18 13:42:34 +02:00
parent fb939868bb
commit 0fa57c451c
25 changed files with 934 additions and 171 deletions

View File

@ -0,0 +1,255 @@
using System.Web.Http;
using WebActivatorEx;
using WebApplication5;
using Swashbuckle.Application;
[assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]
namespace WebApplication5
{
public class SwaggerConfig
{
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
// By default, the service root url is inferred from the request used to access the docs.
// However, there may be situations (e.g. proxy and load-balanced environments) where this does not
// resolve correctly. You can workaround this by providing your own code to determine the root URL.
//
//c.RootUrl(req => GetRootUrlFromAppConfig());
// If schemes are not explicitly provided in a Swagger 2.0 document, then the scheme used to access
// the docs is taken as the default. If your API supports multiple schemes and you want to be explicit
// about them, you can use the "Schemes" option as shown below.
//
//c.Schemes(new[] { "http", "https" });
// Use "SingleApiVersion" to describe a single version API. Swagger 2.0 includes an "Info" object to
// hold additional metadata for an API. Version and title are required but you can also provide
// additional fields by chaining methods off SingleApiVersion.
//
c.SingleApiVersion("v1", "WebApplication5");
// If you want the output Swagger docs to be indented properly, enable the "PrettyPrint" option.
//
//c.PrettyPrint();
// If your API has multiple versions, use "MultipleApiVersions" instead of "SingleApiVersion".
// In this case, you must provide a lambda that tells Swashbuckle which actions should be
// included in the docs for a given API version. Like "SingleApiVersion", each call to "Version"
// returns an "Info" builder so you can provide additional metadata per API version.
//
//c.MultipleApiVersions(
// (apiDesc, targetApiVersion) => ResolveVersionSupportByRouteConstraint(apiDesc, targetApiVersion),
// (vc) =>
// {
// vc.Version("v2", "Swashbuckle Dummy API V2");
// vc.Version("v1", "Swashbuckle Dummy API V1");
// });
// You can use "BasicAuth", "ApiKey" or "OAuth2" options to describe security schemes for the API.
// See https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md for more details.
// NOTE: These only define the schemes and need to be coupled with a corresponding "security" property
// at the document or operation level to indicate which schemes are required for an operation. To do this,
// you'll need to implement a custom IDocumentFilter and/or IOperationFilter to set these properties
// according to your specific authorization implementation
//
//c.BasicAuth("basic")
// .Description("Basic HTTP Authentication");
//
// NOTE: You must also configure 'EnableApiKeySupport' below in the SwaggerUI section
//c.ApiKey("apiKey")
// .Description("API Key Authentication")
// .Name("apiKey")
// .In("header");
//
//c.OAuth2("oauth2")
// .Description("OAuth2 Implicit Grant")
// .Flow("implicit")
// .AuthorizationUrl("http://petstore.swagger.wordnik.com/api/oauth/dialog")
// //.TokenUrl("https://tempuri.org/token")
// .Scopes(scopes =>
// {
// scopes.Add("read", "Read access to protected resources");
// scopes.Add("write", "Write access to protected resources");
// });
// Set this flag to omit descriptions for any actions decorated with the Obsolete attribute
//c.IgnoreObsoleteActions();
// Each operation be assigned one or more tags which are then used by consumers for various reasons.
// For example, the swagger-ui groups operations according to the first tag of each operation.
// By default, this will be controller name but you can use the "GroupActionsBy" option to
// override with any value.
//
//c.GroupActionsBy(apiDesc => apiDesc.HttpMethod.ToString());
// You can also specify a custom sort order for groups (as defined by "GroupActionsBy") to dictate
// the order in which operations are listed. For example, if the default grouping is in place
// (controller name) and you specify a descending alphabetic sort order, then actions from a
// ProductsController will be listed before those from a CustomersController. This is typically
// used to customize the order of groupings in the swagger-ui.
//
//c.OrderActionGroupsBy(new DescendingAlphabeticComparer());
// If you annotate Controllers and API Types with
// Xml comments (http://msdn.microsoft.com/en-us/library/b2s063f7(v=vs.110).aspx), you can incorporate
// those comments into the generated docs and UI. You can enable this by providing the path to one or
// more Xml comment files.
//
//c.IncludeXmlComments(GetXmlCommentsPath());
// Swashbuckle makes a best attempt at generating Swagger compliant JSON schemas for the various types
// exposed in your API. However, there may be occasions when more control of the output is needed.
// This is supported through the "MapType" and "SchemaFilter" options:
//
// Use the "MapType" option to override the Schema generation for a specific type.
// It should be noted that the resulting Schema will be placed "inline" for any applicable Operations.
// While Swagger 2.0 supports inline definitions for "all" Schema types, the swagger-ui tool does not.
// It expects "complex" Schemas to be defined separately and referenced. For this reason, you should only
// use the "MapType" option when the resulting Schema is a primitive or array type. If you need to alter a
// complex Schema, use a Schema filter.
//
//c.MapType<ProductType>(() => new Schema { type = "integer", format = "int32" });
// If you want to post-modify "complex" Schemas once they've been generated, across the board or for a
// specific type, you can wire up one or more Schema filters.
//
//c.SchemaFilter<ApplySchemaVendorExtensions>();
// In a Swagger 2.0 document, complex types are typically declared globally and referenced by unique
// Schema Id. By default, Swashbuckle does NOT use the full type name in Schema Ids. In most cases, this
// works well because it prevents the "implementation detail" of type namespaces from leaking into your
// Swagger docs and UI. However, if you have multiple types in your API with the same class name, you'll
// need to opt out of this behavior to avoid Schema Id conflicts.
//
//c.UseFullTypeNameInSchemaIds();
// Alternatively, you can provide your own custom strategy for inferring SchemaId's for
// describing "complex" types in your API.
//
//c.SchemaId(t => t.FullName.Contains('`') ? t.FullName.Substring(0, t.FullName.IndexOf('`')) : t.FullName);
// Set this flag to omit schema property descriptions for any type properties decorated with the
// Obsolete attribute
//c.IgnoreObsoleteProperties();
// In accordance with the built in JsonSerializer, Swashbuckle will, by default, describe enums as integers.
// You can change the serializer behavior by configuring the StringToEnumConverter globally or for a given
// enum type. Swashbuckle will honor this change out-of-the-box. However, if you use a different
// approach to serialize enums as strings, you can also force Swashbuckle to describe them as strings.
//
//c.DescribeAllEnumsAsStrings();
// Similar to Schema filters, Swashbuckle also supports Operation and Document filters:
//
// Post-modify Operation descriptions once they've been generated by wiring up one or more
// Operation filters.
//
//c.OperationFilter<AddDefaultResponse>();
//
// If you've defined an OAuth2 flow as described above, you could use a custom filter
// to inspect some attribute on each action and infer which (if any) OAuth2 scopes are required
// to execute the operation
//
//c.OperationFilter<AssignOAuth2SecurityRequirements>();
// Post-modify the entire Swagger document by wiring up one or more Document filters.
// This gives full control to modify the final SwaggerDocument. You should have a good understanding of
// the Swagger 2.0 spec. - https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md
// before using this option.
//
//c.DocumentFilter<ApplyDocumentVendorExtensions>();
// In contrast to WebApi, Swagger 2.0 does not include the query string component when mapping a URL
// to an action. As a result, Swashbuckle will raise an exception if it encounters multiple actions
// with the same path (sans query string) and HTTP method. You can workaround this by providing a
// custom strategy to pick a winner or merge the descriptions for the purposes of the Swagger docs
//
//c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
// Wrap the default SwaggerGenerator with additional behavior (e.g. caching) or provide an
// alternative implementation for ISwaggerProvider with the CustomProvider option.
//
//c.CustomProvider((defaultProvider) => new CachingSwaggerProvider(defaultProvider));
})
.EnableSwaggerUi(c =>
{
// Use the "DocumentTitle" option to change the Document title.
// Very helpful when you have multiple Swagger pages open, to tell them apart.
//
//c.DocumentTitle("My Swagger UI");
// Use the "InjectStylesheet" option to enrich the UI with one or more additional CSS stylesheets.
// The file must be included in your project as an "Embedded Resource", and then the resource's
// "Logical Name" is passed to the method as shown below.
//
//c.InjectStylesheet(containingAssembly, "Swashbuckle.Dummy.SwaggerExtensions.testStyles1.css");
// Use the "InjectJavaScript" option to invoke one or more custom JavaScripts after the swagger-ui
// has loaded. The file must be included in your project as an "Embedded Resource", and then the resource's
// "Logical Name" is passed to the method as shown above.
//
//c.InjectJavaScript(thisAssembly, "Swashbuckle.Dummy.SwaggerExtensions.testScript1.js");
// The swagger-ui renders boolean data types as a dropdown. By default, it provides "true" and "false"
// strings as the possible choices. You can use this option to change these to something else,
// for example 0 and 1.
//
//c.BooleanValues(new[] { "0", "1" });
// By default, swagger-ui will validate specs against swagger.io's online validator and display the result
// in a badge at the bottom of the page. Use these options to set a different validator URL or to disable the
// feature entirely.
//c.SetValidatorUrl("http://localhost/validator");
//c.DisableValidator();
// Use this option to control how the Operation listing is displayed.
// It can be set to "None" (default), "List" (shows operations for each resource),
// or "Full" (fully expanded: shows operations and their details).
//
//c.DocExpansion(DocExpansion.List);
// Specify which HTTP operations will have the 'Try it out!' option. An empty paramter list disables
// it for all operations.
//
//c.SupportedSubmitMethods("GET", "HEAD");
// Use the CustomAsset option to provide your own version of assets used in the swagger-ui.
// It's typically used to instruct Swashbuckle to return your version instead of the default
// when a request is made for "index.html". As with all custom content, the file must be included
// in your project as an "Embedded Resource", and then the resource's "Logical Name" is passed to
// the method as shown below.
//
//c.CustomAsset("index", containingAssembly, "YourWebApiProject.SwaggerExtensions.index.html");
// If your API has multiple versions and you've applied the MultipleApiVersions setting
// as described above, you can also enable a select box in the swagger-ui, that displays
// a discovery URL for each version. This provides a convenient way for users to browse documentation
// for different API versions.
//
//c.EnableDiscoveryUrlSelector();
// If your API supports the OAuth2 Implicit flow, and you've described it correctly, according to
// the Swagger 2.0 specification, you can enable UI support as shown below.
//
//c.EnableOAuth2Support(
// clientId: "test-client-id",
// clientSecret: null,
// realm: "test-realm",
// appName: "Swagger UI"
// //additionalQueryStringParams: new Dictionary<string, string>() { { "foo", "bar" } }
//);
// If your API supports ApiKey, you can override the default values.
// "apiKeyIn" can either be "query" or "header"
//
//c.EnableApiKeySupport("apiKey", "header");
});
}
}
}

View File

@ -8,9 +8,12 @@ namespace WebApplication5
{
public AutoMapperProfile()
{
CreateMap(typeof(Category), typeof(CategoryViewModel));
CreateMap(typeof(Question), typeof(QuestionViewModel));
CreateMap(typeof(Answer), typeof(AnswerViewModel));
CreateMap<CategoryViewModel, Category>();
CreateMap<Category, CategoryViewModel>();
CreateMap<QuestionViewModel, Question>();
CreateMap<Question, QuestionViewModel>();
CreateMap<AnswerViewModel, Answer>();
CreateMap<Answer, AnswerViewModel>();
}
}
}

View File

@ -3,8 +3,13 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Extensions.DependencyInjection;
using System.Web.Mvc;
using WebApplication5.Models;
using WebApplication5.Templates;
using System.Threading;
using System.Globalization;
using System.Diagnostics;
namespace WebApplication5.Controllers
{
@ -13,6 +18,10 @@ namespace WebApplication5.Controllers
private readonly IMapper _mapper;
private TestsDbContext _db;
public CRUDController(IServiceCollection serviceDescriptors)
{
}
public CRUDController(TestsDbContext db, IMapper mapper)
{
_mapper = mapper;
@ -25,8 +34,10 @@ namespace WebApplication5.Controllers
public JsonResult GetCategories()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
var result = _mapper.ProjectTo<CategoryViewModel>(_db.Categories);
return Json(result.ToList());
return Json(result.ToList(),JsonRequestBehavior.AllowGet);
}
public JsonResult GetQuestions(int categoryId)
{
@ -36,16 +47,45 @@ namespace WebApplication5.Controllers
public ActionResult PutCategory(CategoryViewModel category)
{
if (category.Id == 0)
try
{
_db.Categories.Add(_mapper.Map<Category>(category));
if (!category.Id.HasValue)
{
try
{
var cat = _mapper.Map<Category>(category);
_db.Categories.Add(cat);
_db.SaveChanges();
}
catch (Exception ex)
{
var i = ex;
try
{
var xy = new Category()
{
Id = 1,
Name = "name"
};
_db.Categories.Add(xy);
_db.SaveChanges();
}
catch (Exception e)
{
var x = 0;
}
}
}
else
{
//_db.Categories.(_mapper.Map<Category>(category));
}
_db.SaveChanges();
}
else
catch (Exception e)
{
_db.Categories.Update(_mapper.Map<Category>(category));
var x = 1;
}
_db.SaveChanges();
return View();
}
public ActionResult PutQuestion(QuestionViewModel question, int categoryId)
@ -62,8 +102,10 @@ namespace WebApplication5.Controllers
c.Questions.Add(q);
}
else
_db.Questions.Update(q);
{
//_db.Questions.Update(q);
}
if (question.Answers.Any())
{
var allAns = question.Answers.Select(an => _mapper.Map<Answer>(an)).ToList();
@ -77,7 +119,7 @@ namespace WebApplication5.Controllers
}
foreach (var a in existingAns)
{
_db.Answers.Update(a);
//_db.Answers.Update(a);
}
}
@ -123,5 +165,33 @@ namespace WebApplication5.Controllers
return View();
}
public ActionResult GeneratePDF(TemplatesOrder templatesToGenerate)
{
var catq1 = new TemplateViewModel()
{
CategoryId = 1,
NumberOfQuestions = 3,
QuestionsIds = new List<int>(){ 1, 2, 3 }
};
var catq2 = new TemplateViewModel()
{
CategoryId = 2,
QuestionsIds = new List<int>(),
NumberOfQuestions = 2
};
templatesToGenerate = new TemplatesOrder()
{
TestName = "Wielki Test1",
NumberOfExamples = 5,
Categories = new List<TemplateViewModel>() { catq1, catq2 }
};
var generator = new TemplateGenerator(_db, templatesToGenerate);
generator.ProcessOrder();
return View();
}
}
}
}

View File

@ -1,31 +0,0 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using WebApplication5.Models;
namespace WebApplication5
{
public class AnswerConfiguration : IEntityTypeConfiguration<Answer>
{
public void Configure(EntityTypeBuilder<Answer> builder)
{
#region Primary Key
builder.HasKey(e => e.Id)
.ForSqlServerIsClustered(true); //it would be more usefull on userId
#endregion
#region Relationships/Keys
builder.HasOne(w => w.Question)
.WithMany(w => w.Answers)
.HasForeignKey(w => w.Id)
.HasConstraintName("FK_Answer_Questions")
.OnDelete(DeleteBehavior.Restrict);
#endregion
#region Properties
builder.Property(e => e.Id)
.ValueGeneratedOnAdd();
#endregion
}
}
}

View File

@ -1,22 +0,0 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using WebApplication5.Models;
namespace WebApplication5
{
public class CategoryConfiguration : IEntityTypeConfiguration<Category>
{
public void Configure(EntityTypeBuilder<Category> builder)
{
#region Primary Key
builder.HasKey(e => e.Id)
.ForSqlServerIsClustered(true); //it would be more usefull on userId
#endregion
#region Properties
builder.Property(e => e.Id)
.ValueGeneratedOnAdd();
#endregion
}
}
}

View File

@ -1,31 +0,0 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using WebApplication5.Models;
namespace WebApplication5
{
public class QuestionConfiguration : IEntityTypeConfiguration<Question>
{
public void Configure(EntityTypeBuilder<Question> builder)
{
#region Primary Key
builder.HasKey(e => e.Id)
.ForSqlServerIsClustered(true); //it would be more usefull on userId
#endregion
#region Relationships/Keys
builder.HasOne(w => w.Category)
.WithMany(w => w.Questions)
.HasForeignKey(w => w.Id)
.HasConstraintName("FK_Category_Answer")
.OnDelete(DeleteBehavior.Restrict);
#endregion
#region Properties
builder.Property(e => e.Id)
.ValueGeneratedOnAdd();
#endregion
}
}
}

View File

@ -1,23 +0,0 @@
using Microsoft.EntityFrameworkCore;
using WebApplication5.Models;
namespace WebApplication5
{
public class TestsDbContext : DbContext
{
public TestsDbContext(DbContextOptions<TestsDbContext> options)
: base(options)
{
}
public DbSet<Question> Questions { get; set; }
public DbSet<Answer> Answers { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(TestsDbContext).Assembly);
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebApplication5.Models.Business
{
public class TemplateAnswer
{
public string Identifier { get; set; }
public string StudendGUID { get; set; }
public List<SimpleAnswer> Answers { get; set; }
}
}

View File

@ -8,7 +8,7 @@ namespace WebApplication5.Models
{
Questions = new List<QuestionViewModel>();
}
public int Id { get; set; }
public int? Id { get; set; }
public string Name { get; set; }
public List<QuestionViewModel> Questions { get; set; }
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebApplication5.Models.Business
{
public class SimpleAnswer
{
public int AnswerNumber { get; set; }
public int CheckBoxNumber { get; set; }
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebApplication5.Models
{
public class TemplateViewModel
{
public List<int> QuestionsIds { get; set; }
public int CategoryId { get; set; }
public int NumberOfQuestions { get; set; }
}
public class TemplatesOrder
{
public List<TemplateViewModel> Categories { get; set; }
public int NumberOfExamples { get; set; }
public string TestName { get; set; }
}
}

View File

@ -0,0 +1,22 @@
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using WebApplication5.Models;
using System.ComponentModel.DataAnnotations.Schema;
namespace WebApplication5
{
public class AnswerConfiguration : EntityTypeConfiguration<Answer>
{
public void Configure(DbModelBuilder builder)
{
#region Primary Key
builder.Entity<Answer>().HasKey(e => e.Id);
#endregion
#region Properties
builder.Entity<Answer>().Property(e => e.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
#endregion
}
}
}

View File

@ -0,0 +1,26 @@
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using WebApplication5.Models;
using System.ComponentModel.DataAnnotations.Schema;
namespace WebApplication5
{
public class CategoryConfiguration : EntityTypeConfiguration<Category>
{
public void Configure(DbModelBuilder builder)
{
#region Primary Key
builder.Entity<Category>().HasKey(e => e.Id);
#endregion
#region Relations
builder.Entity<Category>().HasMany(e => e.Questions);
#endregion
#region Properties
builder.Entity<Category>().Property(e => e.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
#endregion
}
}
}

View File

@ -0,0 +1,27 @@
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using WebApplication5.Models;
using System.ComponentModel.DataAnnotations.Schema;
namespace WebApplication5
{
public class QuestionConfiguration : EntityTypeConfiguration<Question>
{
public void Configure(DbModelBuilder builder)
{
#region Primary Key
builder.Entity<Question>().HasKey(e => e.Id);
#endregion
#region Relations
builder.Entity<Category>().HasMany(e => e.Questions);
#endregion
#region Properties
builder.Entity<Question>().Property(e => e.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
#endregion
}
}
}

View File

@ -0,0 +1,18 @@

using System;
using System.Data.Entity;
using System.Diagnostics;
using WebApplication5.Models;
namespace WebApplication5
{
public class TestsDbContext : DbContext
{
public TestsDbContext(string connString) : base(connString)
{
}
public DbSet<Question> Questions { get; set; }
public DbSet<Answer> Answers { get; set; }
public DbSet<Category> Categories { get; set; }
}
}

View File

@ -3,11 +3,11 @@ using Owin;
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using WebApplication5.Controllers;
using Microsoft.Extensions.DependencyInjection;
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using System.Reflection;
using System.Linq;
using System.Configuration;
[assembly: OwinStartupAttribute(typeof(WebApplication5.Startup))]
namespace WebApplication5
@ -16,6 +16,8 @@ namespace WebApplication5
{
public void Configuration(IAppBuilder app)
{
IocConfiguration.Configure();
ConfigureAuth(app);
//configure auto mapper
@ -29,37 +31,75 @@ namespace WebApplication5
#region AutoMapper
services.AddAutoMapper(new Assembly[] { typeof(AutoMapperProfile).GetTypeInfo().Assembly });
#endregion
services.AddDbContext<TestsDbContext>(options =>
{
options.UseSqlServer("DefaultConnection");
});
services.AddScoped(_ =>
new TestsDbContext(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString)
);
// Register to support the ExampleController can get DbContext.
services.AddTransient(typeof(CRUDController));
services.AddSingleton(_ => new Writer.WriterPDF());
var serviceProvider = services.BuildServiceProvider();
DependencyResolver.SetResolver(new DefaultServiceResolver(serviceProvider));
services.AddSingleton(typeof(AutoMapperProfile));
services.AddControllersAsServices(typeof(Startup).Assembly.GetExportedTypes()
.Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition)
.Where(t => typeof(IController).IsAssignableFrom(t)
|| t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)));
var resolver = new DefaultDependencyResolver(services.BuildServiceProvider());
// Set the application resolver to our default resolver. This comes from "System.Web.Mvc"
//Other services may be added elsewhere through time
DependencyResolver.SetResolver(resolver);
}
}
public class DefaultDependencyResolver : IDependencyResolver
{
/// <summary>
/// Provides the service that holds the services
/// </summary>
protected IServiceProvider serviceProvider;
/// <summary>
/// Create the service resolver using the service provided (Direct Injection pattern)
/// </summary>
/// <param name="serviceProvider"></param>
public DefaultDependencyResolver(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
/// <summary>
/// Get a service by type - assume you get the first one encountered
/// </summary>
/// <param name="serviceType"></param>
/// <returns></returns>
public object GetService(Type serviceType)
{
return this.serviceProvider.GetService(serviceType);
}
/// <summary>
/// Get all services of a type
/// </summary>
/// <param name="serviceType"></param>
/// <returns></returns>
public IEnumerable<object> GetServices(Type serviceType)
{
return this.serviceProvider.GetServices(serviceType);
}
}
public class DefaultServiceResolver : IDependencyResolver
}
public static class ServiceProviderExtensions
{
public static IServiceCollection AddControllersAsServices(this IServiceCollection services, IEnumerable<Type> serviceTypes)
{
private readonly IServiceProvider _serviceProvider;
public DefaultServiceResolver(IServiceProvider serviceProvider)
foreach (var type in serviceTypes)
{
_serviceProvider = serviceProvider;
services.AddTransient(type);
}
public object GetService(Type serviceType)
{
return _serviceProvider.GetService(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _serviceProvider.GetServices(serviceType);
}
return services;
}
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using WebApplication5.Models.Business;
namespace WebApplication5.Templates
{
public class CheckCards
{
//inject db
public CheckCards()
{
}
public List<TemplateAnswer> LoadAnswersPdf()
{
var list = new List<TemplateAnswer>();
while (false) //while pdf not ended
{
//read page
var studentAns = new TemplateAnswer();
//Extract identifier
//Extract student info
//ExtractAnswers
}
return list;
}
public void AssignPointsToStudent(TemplateAnswer answers)
{
//load template for guid in answer
//check number of valid answers
//assign score
}
}
}

View File

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using WebApplication5.Models;
using WebApplication5.Writer;
namespace WebApplication5.Templates
{
public class TemplateGenerator
{
private TestsDbContext _db;
private TemplatesOrder _templatesOrder;
private string fileName = Guid.NewGuid().ToString();
private WriterPDF writer= new WriterPDF();
public TemplateGenerator(TestsDbContext db, TemplatesOrder templatesOrder)
{
_db = db;
_templatesOrder = templatesOrder;
}
public void ProcessOrder()
{
writer.CreateFile(fileName);
for (int i = 0; i < _templatesOrder.NumberOfExamples; i++)
{
var questionNumber = 1;
writer.WriteTitle(_templatesOrder.TestName);
var questions = new List<Question>();
foreach (var cat in _templatesOrder.Categories)
{
writer.WriteCategory(_db.Categories.First(c => c.Id == cat.CategoryId).Name);
var catQuestions = GetQuestionsForCategory(cat);
writer.WriteQuestions(catQuestions, questionNumber);
questionNumber += catQuestions.Count;
questions = questions.Concat(catQuestions)
.ToList();
}
writer.EndPage();
writer.WriteAnswerTemplate(questions, string.Join("_", questions.Select(q => q.Id)));
//TODO
//wrtie to DB
//QRcode + questions
}
writer.CloseFile();
}
private List<Question> GetQuestionsForCategory(TemplateViewModel templatesToGenerate)
{
var questions = _db.Questions.Include("Answers").Where(q => q.CategoryId == templatesToGenerate.CategoryId).ToList();
if (templatesToGenerate.QuestionsIds.Any())
{
questions = questions
.Where(q => templatesToGenerate.QuestionsIds.Contains(q.Id))
.ToList();
}
else
{
questions = questions
.OrderBy(arg => Guid.NewGuid()).Take(templatesToGenerate.NumberOfQuestions)
.ToList();
}
return questions;
}
}
}

View File

@ -0,0 +1,223 @@
using iTextSharp.text;
using iTextSharp.text.pdf;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using WebApplication5.Models;
namespace WebApplication5.Writer
{
public class WriterPDF
{
private static string[] listOfPodpunkty = new string[] { "a", "b", "c", "d", "e", "f", "g", "h" };
private static Font catFont = new Font(Font.FontFamily.TIMES_ROMAN, 14,
Font.BOLD);
private static Font titleFont = new Font(Font.FontFamily.TIMES_ROMAN, 16,
Font.BOLD);
Document document;
PdfContentByte cb;
PdfWriter writer;
FileStream fs;
public void WriteQuestions(List<Question> questions, int questionNumber)
{
var localQuestionCount = 0;
foreach (var question in questions)
{
WriteQuestion(question.QuestionText, questionNumber + localQuestionCount);
WriteAnswers(question.Answers.ToList());
localQuestionCount++;
}
}
public void CreateFile(string fileName)
{
var path = @"C:\Users\Janek\Desktop\Tests\";
document = new Document();
// open the writer
fs = new FileStream(path + fileName + ".pdf", FileMode.Create, FileAccess.Write);
writer = PdfWriter.GetInstance(document, fs);
document.Open();
// the pdf content
cb = writer.DirectContent;
}
private void WriteQuestion(string question, int questionNumber)
{
document.Add(new Paragraph(string.Format("{0}. {1}", questionNumber, question)));
}
private string FormatAnswer(int letter, string answer)
{
return string.Format("{0}) {1}", listOfPodpunkty[letter], answer);
}
private void WriteAnswers(List<Answer> answers)
{
PdfPTable table = new PdfPTable(2);
table.WidthPercentage = 90;
table.DefaultCell.Border = 0;
for (int i = 0; i < answers.Count; i++)
{
table.AddCell(FormatAnswer(i, answers.ElementAt(i).AnswerText));
}
if (answers.Count % 2 == 1)
{
var cell = new PdfPCell(new Phrase(" "));
cell.Border = 0;
table.AddCell(cell);
}
document.Add(table);
}
public void WriteTitle(string title)
{
document.AddTitle(title);
var phar = new Paragraph();
phar.Add(new Paragraph(title, titleFont));
document.Add(phar);
}
public void WriteCategory(string cat)
{
var phar = new Paragraph();
AddEmptyLine(phar, 1);
phar.Add(new Paragraph(cat, catFont));
AddEmptyLine(phar, 1);
document.Add(phar);
}
public void EndPage()
{
document.NewPage();
}
private static void AddEmptyLine(Paragraph paragraph, int number)
{
for (int i = 0; i < number; i++)
{
paragraph.Add(new Paragraph(" "));
}
}
public void CloseFile()
{
document.Close();
fs.Close();
writer.Close();
}
public void WriteAnswerTemplate(List<Question> questions,string qrCode)
{
AddUserId();
WriteTitle("Odpowiedzi");
PdfPTable outer = new PdfPTable(2);
outer.WidthPercentage = 95;
outer.HorizontalAlignment = Element.ALIGN_LEFT;
var size = questions.Count - (questions.Count / 2);
var isEven = questions.Count % 2 == 0;
outer.DefaultCell.Border = 0;
outer.AddCell(CreateAnswersTable(questions.Take(size).ToList(), 0));
outer.AddCell(CreateAnswersTable(questions.Skip(size).ToList(), size, isEven));
document.Add(outer);
AddQRCode(qrCode);
EndPage();
}
private PdfPTable CreateAnswersTable(List<Question> questions, int moved, bool isEven = false)
{
var maxWidth = questions.Max(t => t.Answers.Count) + 1;
var table = new PdfPTable(maxWidth);
table.DefaultCell.Border = 0;
table.HorizontalAlignment = Element.ALIGN_LEFT;
var cornerCell = new PdfPCell(new Phrase(" "));
cornerCell.Border = 0;
table.AddCell(cornerCell);
var widths = new List<float>();
var ratio = (5 * maxWidth - 2);
var percentage = 100 / ratio;
var rest = 100 % ratio;
widths.Add(2 * percentage + rest);
for (int i = 1; i < maxWidth; i++)
{
widths.Add(percentage * 5);
}
table.SetWidthPercentage(widths.ToArray(), document.PageSize);
for (int k = 0; k < maxWidth - 1; k++)
{
var lettersCell = new PdfPCell(new Phrase(listOfPodpunkty[k]));
lettersCell.Border = 0;
lettersCell.HorizontalAlignment = Element.ALIGN_CENTER;
table.AddCell(lettersCell);
}
for (int i = 0; i < questions.Count; i++)
{
var ansCount = 1;
var numberCell = new PdfPCell(new Phrase(string.Format("{0}.", i + 1 + moved)));
numberCell.Border = 0;
numberCell.HorizontalAlignment = Element.ALIGN_RIGHT;
table.AddCell(numberCell);
foreach (var a in questions.ElementAt(i).Answers)
{
var answerCell = new PdfPCell(new Phrase(" "));
answerCell.Border = 15;
table.AddCell(answerCell);
ansCount++;
}
for (int j = ansCount; j < maxWidth; j++)
{
var emptyAnswerCell = new PdfPCell(new Phrase(" "));
emptyAnswerCell.Border = 0;
table.AddCell(emptyAnswerCell);
}
}
if (!isEven)
{
for (int j = 0; j < maxWidth; j++)
{
var emptyAnswerCell = new PdfPCell(new Phrase(" "));
emptyAnswerCell.Border = 0;
table.AddCell(emptyAnswerCell);
}
}
return table;
}
private void AddQRCode(string salt)
{
var qrcode = new BarcodeQRCode(salt, 100, 100, null);
var image = qrcode.GetImage();
var mask = qrcode.GetImage();
mask.MakeMask();
image.ImageMask = mask; // making the background color transparent
image.SetAbsolutePosition(document.PageSize.Width - document.RightMargin - 80, document.PageSize.Height - document.TopMargin - 80);
document.Add(image);
}
private void AddUserId()
{
WriteTitle("PESEL");
PdfPTable table = new PdfPTable(11);
table.SpacingBefore = 10;
table.WidthPercentage = 50;
table.HorizontalAlignment = Element.ALIGN_LEFT;
for (int i = 0; i < 11; i++)
table.AddCell(" ");
document.Add(table);
}
}
}

View File

@ -9,10 +9,10 @@
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-WebApplication5-20200114085938.mdf;Initial Catalog=aspnet-WebApplication5-20200114085938;Integrated Security=True" providerName="System.Data.SqlClient" />
<add name="DefaultConnection" connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\Janek\Documents\Test123.mdf;Integrated Security=True;App=EntityFramework" providerName="System.Data.SqlClient" />
</connectionStrings>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
@ -26,7 +26,14 @@
<modules>
<remove name="FormsAuthentication" />
</modules>
</system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers></system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>

View File

@ -51,6 +51,9 @@
<Reference Include="AutoMapper.Extensions.Microsoft.DependencyInjection, Version=0.0.0.0, Culture=neutral, PublicKeyToken=e767ac9c89543656, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.Extensions.Microsoft.DependencyInjection.7.0.0\lib\netstandard2.0\AutoMapper.Extensions.Microsoft.DependencyInjection.dll</HintPath>
</Reference>
<Reference Include="itextsharp, Version=5.5.13.1, Culture=neutral, PublicKeyToken=8354ae6d2174ddca, processorArchitecture=MSIL">
<HintPath>..\packages\iTextSharp.5.5.13.1\lib\itextsharp.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
@ -58,18 +61,6 @@
<HintPath>..\packages\Microsoft.Bcl.HashCode.1.1.0\lib\net461\Microsoft.Bcl.HashCode.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.EntityFrameworkCore, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.EntityFrameworkCore.2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll</HintPath>
</Reference>
<Reference Include="Microsoft.EntityFrameworkCore.Abstractions, Version=2.2.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.EntityFrameworkCore.Abstractions.2.2.1\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.EntityFrameworkCore.Relational, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.EntityFrameworkCore.Relational.2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Relational.dll</HintPath>
</Reference>
<Reference Include="Microsoft.EntityFrameworkCore.SqlServer, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.EntityFrameworkCore.SqlServer.2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.SqlServer.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Caching.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Caching.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll</HintPath>
</Reference>
@ -127,6 +118,9 @@
<Reference Include="Remotion.Linq, Version=2.2.0.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
<HintPath>..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll</HintPath>
</Reference>
<Reference Include="Swashbuckle.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cd1bb07a5ac7c7bc, processorArchitecture=MSIL">
<HintPath>..\packages\Swashbuckle.Core.5.6.0\lib\net40\Swashbuckle.Core.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
@ -151,6 +145,9 @@
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.Formatting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.WebApi.Client.4.0.20710.0\lib\net40\System.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
@ -176,6 +173,12 @@
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.WebApi.Core.4.0.20710.0\lib\net40\System.Web.Http.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http.WebHost, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.20710.0\lib\net40\System.Web.Http.WebHost.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Extensions" />
@ -220,6 +223,9 @@
<Private>True</Private>
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
</Reference>
<Reference Include="WebActivatorEx, Version=2.0.0.0, Culture=neutral, PublicKeyToken=7b26dc2a43f6a0d4, processorArchitecture=MSIL">
<HintPath>..\packages\WebActivatorEx.2.0\lib\net40\WebActivatorEx.dll</HintPath>
</Reference>
<Reference Include="WebGrease">
<Private>True</Private>
<HintPath>..\packages\WebGrease.1.6.0\lib\WebGrease.dll</HintPath>
@ -285,28 +291,35 @@
<Compile Include="App_Start\IdentityConfig.cs" />
<Compile Include="App_Start\RouteConfig.cs" />
<Compile Include="App_Start\Startup.Auth.cs" />
<Compile Include="App_Start\SwaggerConfig.cs" />
<Compile Include="Controllers\AccountController.cs" />
<Compile Include="Controllers\CRUDController.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Controllers\ManageController.cs" />
<Compile Include="EF\DbEntities\Configurations\QuestionConfig.cs" />
<Compile Include="EF\DbEntities\Configurations\AnswerConfig.cs" />
<Compile Include="EF\DbEntities\Configurations\CategoryConfig.cs" />
<Compile Include="EF\TestsContext.cs" />
<Compile Include="Models\EF\DbEntities\Answer.cs" />
<Compile Include="Models\EF\DbEntities\Category.cs" />
<Compile Include="Models\EF\DbEntities\Configurations\AnswerConfig.cs" />
<Compile Include="Models\EF\DbEntities\Configurations\CategoryConfig.cs" />
<Compile Include="Models\EF\DbEntities\Configurations\QuestionConfig.cs" />
<Compile Include="Models\EF\DbEntities\Question.cs" />
<Compile Include="Models\EF\TestsContext.cs" />
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
<Compile Include="Models\AccountViewModels.cs" />
<Compile Include="Models\Business\AnswersPDF.cs" />
<Compile Include="Models\Business\AnswerViewModel.cs" />
<Compile Include="Models\Business\QuestionViewModel.cs" />
<Compile Include="EF\DbEntities\Answer.cs" />
<Compile Include="EF\DbEntities\Category.cs" />
<Compile Include="EF\DbEntities\Question.cs" />
<Compile Include="Models\Business\SimpleAnswer.cs" />
<Compile Include="Models\Business\TemplateViewModel.cs" />
<Compile Include="Models\IdentityModels.cs" />
<Compile Include="Models\ManageViewModels.cs" />
<Compile Include="AutoMapperProfile.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Startup.cs" />
<Compile Include="Templates\CheckTemplate.cs" />
<Compile Include="Templates\TemplateGenerator.cs" />
<Compile Include="Templates\Writer.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Content\bootstrap-theme.css" />
@ -368,6 +381,10 @@
</ItemGroup>
<ItemGroup>
<Folder Include="App_Data\" />
<Folder Include="Views\Category\" />
<Folder Include="Views\Question\" />
<Folder Include="Views\Results\" />
<Folder Include="Views\Templates\" />
</ItemGroup>
<ItemGroup>
<Content Include="fonts\glyphicons-halflings-regular.woff2" />

View File

@ -5,6 +5,7 @@
<package id="AutoMapper.Extensions.Microsoft.DependencyInjection" version="7.0.0" targetFramework="net472" />
<package id="bootstrap" version="3.4.1" targetFramework="net472" />
<package id="EntityFramework" version="6.2.0" targetFramework="net472" />
<package id="iTextSharp" version="5.5.13.1" targetFramework="net472" />
<package id="jQuery" version="3.3.1" targetFramework="net472" />
<package id="jQuery.Validation" version="1.17.0" targetFramework="net472" />
<package id="Microsoft.AspNet.Identity.Core" version="2.2.2" targetFramework="net472" />
@ -13,15 +14,14 @@
<package id="Microsoft.AspNet.Mvc" version="5.2.7" targetFramework="net472" />
<package id="Microsoft.AspNet.Razor" version="3.2.7" targetFramework="net472" />
<package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net472" />
<package id="Microsoft.AspNet.WebApi.Client" version="4.0.20710.0" targetFramework="net472" />
<package id="Microsoft.AspNet.WebApi.Core" version="4.0.20710.0" targetFramework="net472" />
<package id="Microsoft.AspNet.WebApi.WebHost" version="4.0.20710.0" targetFramework="net472" />
<package id="Microsoft.AspNet.WebPages" version="3.2.7" targetFramework="net472" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="1.1.0" targetFramework="net472" />
<package id="Microsoft.Bcl.HashCode" version="1.1.0" targetFramework="net472" />
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="2.0.0" targetFramework="net472" />
<package id="Microsoft.EntityFrameworkCore" version="2.2.0" targetFramework="net472" />
<package id="Microsoft.EntityFrameworkCore.Abstractions" version="2.2.1" targetFramework="net472" />
<package id="Microsoft.EntityFrameworkCore.Analyzers" version="3.1.0" targetFramework="net472" />
<package id="Microsoft.EntityFrameworkCore.Relational" version="2.2.0" targetFramework="net472" />
<package id="Microsoft.EntityFrameworkCore.SqlServer" version="2.2.0" targetFramework="net472" />
<package id="Microsoft.Extensions.Caching.Abstractions" version="3.1.0" targetFramework="net472" />
<package id="Microsoft.Extensions.Caching.Memory" version="3.1.0" targetFramework="net472" />
<package id="Microsoft.Extensions.Configuration" version="3.1.0" targetFramework="net472" />
@ -40,6 +40,7 @@
<package id="Microsoft.Extensions.Options" version="3.1.0" targetFramework="net472" />
<package id="Microsoft.Extensions.Primitives" version="3.1.0" targetFramework="net472" />
<package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.11" targetFramework="net472" />
<package id="Microsoft.Net.Http" version="2.0.20710.0" targetFramework="net472" />
<package id="Microsoft.Owin" version="4.0.0" targetFramework="net472" />
<package id="Microsoft.Owin.Host.SystemWeb" version="4.0.0" targetFramework="net472" />
<package id="Microsoft.Owin.Security" version="4.0.0" targetFramework="net472" />
@ -54,6 +55,8 @@
<package id="Newtonsoft.Json" version="11.0.2" targetFramework="net472" />
<package id="Owin" version="1.0" targetFramework="net472" />
<package id="Remotion.Linq" version="2.2.0" targetFramework="net472" />
<package id="Swashbuckle" version="5.6.0" targetFramework="net472" />
<package id="Swashbuckle.Core" version="5.6.0" targetFramework="net472" />
<package id="System.Buffers" version="4.5.0" targetFramework="net472" />
<package id="System.Collections.Immutable" version="1.7.0" targetFramework="net472" />
<package id="System.ComponentModel.Annotations" version="4.7.0" targetFramework="net472" />
@ -67,5 +70,6 @@
<package id="System.Text.Json" version="4.7.0" targetFramework="net472" />
<package id="System.Threading.Tasks.Extensions" version="4.5.2" targetFramework="net472" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net472" />
<package id="WebActivatorEx" version="2.0" targetFramework="net472" />
<package id="WebGrease" version="1.6.0" targetFramework="net472" />
</packages>