Add project files.
commit
1cd0b53843
|
@ -0,0 +1,63 @@
|
|||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
|
@ -0,0 +1,340 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- Backup*.rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29926.136
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iPackage", "iPackage\iPackage.csproj", "{89B4DF42-8C47-4EEB-A9BC-C2FD28840B79}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iPackage.Core.Web", "iPackage.Core.Web\iPackage.Core.Web.csproj", "{7CCC7600-7665-41AE-808A-9EAA3B0C612F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NugetTest.AspCore", "NugetTest.AspCore\NugetTest.AspCore.csproj", "{844D3BD3-D1E6-4A87-9091-5275C6B34BE1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{89B4DF42-8C47-4EEB-A9BC-C2FD28840B79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{89B4DF42-8C47-4EEB-A9BC-C2FD28840B79}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{89B4DF42-8C47-4EEB-A9BC-C2FD28840B79}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{89B4DF42-8C47-4EEB-A9BC-C2FD28840B79}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7CCC7600-7665-41AE-808A-9EAA3B0C612F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7CCC7600-7665-41AE-808A-9EAA3B0C612F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7CCC7600-7665-41AE-808A-9EAA3B0C612F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7CCC7600-7665-41AE-808A-9EAA3B0C612F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{844D3BD3-D1E6-4A87-9091-5275C6B34BE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{844D3BD3-D1E6-4A87-9091-5275C6B34BE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{844D3BD3-D1E6-4A87-9091-5275C6B34BE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{844D3BD3-D1E6-4A87-9091-5275C6B34BE1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {936B5BAE-1CDD-44F3-80DF-C694407D97D2}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,103 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using iPackage.Core.Web.Models.Entity;
|
||||
|
||||
namespace NugetTest.AspCore.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationContext))]
|
||||
[Migration("20201028205435_init")]
|
||||
partial class init
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "5.0.0-preview.5.20278.2")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("NugetTest.AspCore.Models.Article", b =>
|
||||
{
|
||||
b.Property<int>("ArticleId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<string>("Content")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsRemoved")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("PersonId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("RemoveTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("ArticleId");
|
||||
|
||||
b.HasIndex("PersonId");
|
||||
|
||||
b.ToTable("Articles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NugetTest.AspCore.Models.Person", b =>
|
||||
{
|
||||
b.Property<int>("PersonId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("FamilyName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("FirstName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<bool>("IsRemoved")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int?>("PersonId1")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("RemoveTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("PersonId");
|
||||
|
||||
b.HasIndex("PersonId1");
|
||||
|
||||
b.ToTable("People");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NugetTest.AspCore.Models.Article", b =>
|
||||
{
|
||||
b.HasOne("NugetTest.AspCore.Models.Person", "Person")
|
||||
.WithMany()
|
||||
.HasForeignKey("PersonId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NugetTest.AspCore.Models.Person", b =>
|
||||
{
|
||||
b.HasOne("NugetTest.AspCore.Models.Person", null)
|
||||
.WithMany("Persons")
|
||||
.HasForeignKey("PersonId1");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace NugetTest.AspCore.Migrations
|
||||
{
|
||||
public partial class init : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "People",
|
||||
columns: table => new
|
||||
{
|
||||
PersonId = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
IsRemoved = table.Column<bool>(type: "bit", nullable: false),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
RemoveTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
FirstName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
FamilyName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
PersonId1 = table.Column<int>(type: "int", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_People", x => x.PersonId);
|
||||
table.ForeignKey(
|
||||
name: "FK_People_People_PersonId1",
|
||||
column: x => x.PersonId1,
|
||||
principalTable: "People",
|
||||
principalColumn: "PersonId",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Articles",
|
||||
columns: table => new
|
||||
{
|
||||
ArticleId = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
IsRemoved = table.Column<bool>(type: "bit", nullable: false),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
RemoveTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
Content = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
PersonId = table.Column<int>(type: "int", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Articles", x => x.ArticleId);
|
||||
table.ForeignKey(
|
||||
name: "FK_Articles_People_PersonId",
|
||||
column: x => x.PersonId,
|
||||
principalTable: "People",
|
||||
principalColumn: "PersonId",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Articles_PersonId",
|
||||
table: "Articles",
|
||||
column: "PersonId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_People_PersonId1",
|
||||
table: "People",
|
||||
column: "PersonId1");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Articles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "People");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using iPackage.Core.Web.Models.Entity;
|
||||
|
||||
namespace NugetTest.AspCore.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationContext))]
|
||||
partial class ApplicationContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "5.0.0-preview.5.20278.2")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("NugetTest.AspCore.Models.Article", b =>
|
||||
{
|
||||
b.Property<int>("ArticleId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<string>("Content")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsRemoved")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("PersonId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("RemoveTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("ArticleId");
|
||||
|
||||
b.HasIndex("PersonId");
|
||||
|
||||
b.ToTable("Articles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NugetTest.AspCore.Models.Person", b =>
|
||||
{
|
||||
b.Property<int>("PersonId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("FamilyName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("FirstName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<bool>("IsRemoved")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int?>("PersonId1")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("RemoveTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("PersonId");
|
||||
|
||||
b.HasIndex("PersonId1");
|
||||
|
||||
b.ToTable("People");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NugetTest.AspCore.Models.Article", b =>
|
||||
{
|
||||
b.HasOne("NugetTest.AspCore.Models.Person", "Person")
|
||||
.WithMany()
|
||||
.HasForeignKey("PersonId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NugetTest.AspCore.Models.Person", b =>
|
||||
{
|
||||
b.HasOne("NugetTest.AspCore.Models.Person", null)
|
||||
.WithMany("Persons")
|
||||
.HasForeignKey("PersonId1");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using iPackage.Models.Entity;
|
||||
|
||||
namespace NugetTest.AspCore.Models
|
||||
{
|
||||
public class Article : ApiEntity
|
||||
{
|
||||
public int ArticleId { get; set; }
|
||||
public string Content { get; set; }
|
||||
public int PersonId { get; set; }
|
||||
public Person Person { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using iPackage.Models.Entity;
|
||||
|
||||
namespace NugetTest.AspCore.Models
|
||||
{
|
||||
public class Person : ApiEntity
|
||||
{
|
||||
[Key]
|
||||
public int PersonId { get; set; }
|
||||
|
||||
public string FirstName { get; set; }
|
||||
public string FamilyName { get; set; }
|
||||
public ICollection<Person> Persons { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\iPackage.Core.Web\iPackage.Core.Web.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Migrations\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,26 @@
|
|||
@page
|
||||
@model ErrorModel
|
||||
@{
|
||||
ViewData["Title"] = "Error";
|
||||
}
|
||||
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
@if (Model.ShowRequestId)
|
||||
{
|
||||
<p>
|
||||
<strong>Request ID:</strong> <code>@Model.RequestId</code>
|
||||
</p>
|
||||
}
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||
It can result in displaying sensitive information from exceptions to end users.
|
||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||
and restarting the app.
|
||||
</p>
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace NugetTest.AspCore.Pages
|
||||
{
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public class ErrorModel : PageModel
|
||||
{
|
||||
public string RequestId { get; set; }
|
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
|
||||
private readonly ILogger<ErrorModel> _logger;
|
||||
|
||||
public ErrorModel(ILogger<ErrorModel> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
@page
|
||||
@model IndexModel
|
||||
@{
|
||||
ViewData["Title"] = "Home page";
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h1 class="display-4">Welcome</h1>
|
||||
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
|
||||
</div>
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace NugetTest.AspCore.Pages
|
||||
{
|
||||
public class IndexModel : PageModel
|
||||
{
|
||||
private readonly ILogger<IndexModel> _logger;
|
||||
|
||||
public IndexModel(ILogger<IndexModel> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
@page
|
||||
@model PrivacyModel
|
||||
@{
|
||||
ViewData["Title"] = "Privacy Policy";
|
||||
}
|
||||
<h1>@ViewData["Title"]</h1>
|
||||
|
||||
<p>Use this page to detail your site's privacy policy.</p>
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace NugetTest.AspCore.Pages
|
||||
{
|
||||
public class PrivacyModel : PageModel
|
||||
{
|
||||
private readonly ILogger<PrivacyModel> _logger;
|
||||
|
||||
public PrivacyModel(ILogger<PrivacyModel> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - NugetTest.AspCore</title>
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="~/css/site.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" asp-area="" asp-page="/Index">NugetTest.AspCore</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
|
||||
<ul class="navbar-nav flex-grow-1">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<div class="container">
|
||||
<main role="main" class="pb-3">
|
||||
@RenderBody()
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<footer class="border-top footer text-muted">
|
||||
<div class="container">
|
||||
© 2020 - NugetTest.AspCore - <a asp-area="" asp-page="/Privacy">Privacy</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||
|
||||
@RenderSection("Scripts", required: false)
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,2 @@
|
|||
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
|
||||
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
|
|
@ -0,0 +1,3 @@
|
|||
@using NugetTest.AspCore
|
||||
@namespace NugetTest.AspCore.Pages
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
|
@ -0,0 +1,3 @@
|
|||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace NugetTest.AspCore
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:63549",
|
||||
"sslPort": 44338
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"NugetTest.AspCore": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using iPackage.Core.Web;
|
||||
using iPackage.Core.Web.Extensions;
|
||||
using iPackage.Core.Web.Models.Entity;
|
||||
using iPackage.Core.Web.WebFramework.Configurations;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.HttpsPolicy;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace NugetTest.AspCore
|
||||
{
|
||||
public class Startup : iPackageStartup<Startup>
|
||||
{
|
||||
public Startup(Microsoft.AspNetCore.Hosting.IHostingEnvironment env) : base(env)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
base.ConfigureServices(services);
|
||||
|
||||
services.AddiPackageDbContext<ApplicationIdentityContext,Startup>(options =>
|
||||
{
|
||||
options.UseProjectAssembly(typeof(Startup).Assembly);
|
||||
options.UseSqlServer(Configuration.GetConnectionString("LocalConnection"),
|
||||
b => b.MigrationsAssembly("NugetTest.AspCore"));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"LocalConnection": "Server=.;Database=NugetTest;Trusted_Connection=true;",
|
||||
"MySqlConnection": "Server=localhost;Port=3306;Database=myDataBase;Uid=root;",
|
||||
"ServerConnection": "server=.\\MSSQLSERVER2016;database=persia20_driv;uid=amirm;pwd=Amdemon@1377"
|
||||
},
|
||||
"SiteSettings": {
|
||||
"BaseUrl": "http://localhost/TelegramBotCore",
|
||||
"Published": false,
|
||||
"CrushBot": "1181122751:AAFh2FjdIcv57GAKfrzrWBbuQwQyEPkbis4",
|
||||
"UnknownBot": "406964183:AAHUJvqN5EdFXvNv8zRjqpLiVzvbpoX3-dY",
|
||||
"GetProfilePicture": null,
|
||||
"UserSetting": {
|
||||
"Username": "Root",
|
||||
"Email": "Admin@gmail.com",
|
||||
"Password": "root1234",
|
||||
"Phone": "09211111111",
|
||||
"RoleName": "RootAdmin",
|
||||
"FirstName": "مدیر",
|
||||
"LastName": "سیستم"
|
||||
},
|
||||
"JwtSettings": {
|
||||
"SecretKey": "GodProtectedKeyCrushBot",
|
||||
"Issuer": "mywebsite",
|
||||
"Audience": "mywebsite",
|
||||
"ExpireAddDay": "15"
|
||||
}
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
|
||||
for details on configuring this project to bundle and minify static web assets. */
|
||||
|
||||
a.navbar-brand {
|
||||
white-space: normal;
|
||||
text-align: center;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* Provide sufficient contrast against white background */
|
||||
a {
|
||||
color: #0366d6;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
/* Sticky footer styles
|
||||
-------------------------------------------------- */
|
||||
html {
|
||||
font-size: 14px;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
html {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.border-top {
|
||||
border-top: 1px solid #e5e5e5;
|
||||
}
|
||||
.border-bottom {
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.box-shadow {
|
||||
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
|
||||
}
|
||||
|
||||
button.accept-policy {
|
||||
font-size: 1rem;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
/* Sticky footer styles
|
||||
-------------------------------------------------- */
|
||||
html {
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
/* Margin bottom by footer height */
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
.footer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
line-height: 60px; /* Vertically center the text there */
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
|
@ -0,0 +1,4 @@
|
|||
// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
|
||||
// for details on configuring this project to bundle and minify static web assets.
|
||||
|
||||
// Write your Javascript code.
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2018 Twitter, Inc.
|
||||
Copyright (c) 2011-2018 The Bootstrap Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,331 @@
|
|||
/*!
|
||||
* Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2019 The Bootstrap Authors
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #212529;
|
||||
text-align: left;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
[tabindex="-1"]:focus {
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title],
|
||||
abbr[data-original-title] {
|
||||
text-decoration: underline;
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
border-bottom: 0;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: .5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #0056b3;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]) {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]):focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
svg {
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
color: #6c757d;
|
||||
text-align: left;
|
||||
caption-side: bottom;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
outline: 1px dotted;
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
input {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
button,
|
||||
[type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
button:not(:disabled),
|
||||
[type="button"]:not(:disabled),
|
||||
[type="reset"]:not(:disabled),
|
||||
[type="submit"]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input[type="date"],
|
||||
input[type="time"],
|
||||
input[type="datetime-local"],
|
||||
input[type="month"] {
|
||||
-webkit-appearance: listbox;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: .5rem;
|
||||
font-size: 1.5rem;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type="search"] {
|
||||
outline-offset: -2px;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,8 @@
|
|||
/*!
|
||||
* Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2019 The Bootstrap Authors
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
|
||||
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,12 @@
|
|||
Copyright (c) .NET Foundation. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
these files except in compliance with the License. You may obtain a copy of the
|
||||
License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
|
@ -0,0 +1,432 @@
|
|||
// Unobtrusive validation support library for jQuery and jQuery Validate
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// @version v3.2.11
|
||||
|
||||
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
|
||||
/*global document: false, jQuery: false */
|
||||
|
||||
(function (factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define("jquery.validate.unobtrusive", ['jquery-validation'], factory);
|
||||
} else if (typeof module === 'object' && module.exports) {
|
||||
// CommonJS-like environments that support module.exports
|
||||
module.exports = factory(require('jquery-validation'));
|
||||
} else {
|
||||
// Browser global
|
||||
jQuery.validator.unobtrusive = factory(jQuery);
|
||||
}
|
||||
}(function ($) {
|
||||
var $jQval = $.validator,
|
||||
adapters,
|
||||
data_validation = "unobtrusiveValidation";
|
||||
|
||||
function setValidationValues(options, ruleName, value) {
|
||||
options.rules[ruleName] = value;
|
||||
if (options.message) {
|
||||
options.messages[ruleName] = options.message;
|
||||
}
|
||||
}
|
||||
|
||||
function splitAndTrim(value) {
|
||||
return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
|
||||
}
|
||||
|
||||
function escapeAttributeValue(value) {
|
||||
// As mentioned on http://api.jquery.com/category/selectors/
|
||||
return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
|
||||
}
|
||||
|
||||
function getModelPrefix(fieldName) {
|
||||
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
|
||||
}
|
||||
|
||||
function appendModelPrefix(value, prefix) {
|
||||
if (value.indexOf("*.") === 0) {
|
||||
value = value.replace("*.", prefix);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function onError(error, inputElement) { // 'this' is the form element
|
||||
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
|
||||
replaceAttrValue = container.attr("data-valmsg-replace"),
|
||||
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
|
||||
|
||||
container.removeClass("field-validation-valid").addClass("field-validation-error");
|
||||
error.data("unobtrusiveContainer", container);
|
||||
|
||||
if (replace) {
|
||||
container.empty();
|
||||
error.removeClass("input-validation-error").appendTo(container);
|
||||
}
|
||||
else {
|
||||
error.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function onErrors(event, validator) { // 'this' is the form element
|
||||
var container = $(this).find("[data-valmsg-summary=true]"),
|
||||
list = container.find("ul");
|
||||
|
||||
if (list && list.length && validator.errorList.length) {
|
||||
list.empty();
|
||||
container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
|
||||
|
||||
$.each(validator.errorList, function () {
|
||||
$("<li />").html(this.message).appendTo(list);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function onSuccess(error) { // 'this' is the form element
|
||||
var container = error.data("unobtrusiveContainer");
|
||||
|
||||
if (container) {
|
||||
var replaceAttrValue = container.attr("data-valmsg-replace"),
|
||||
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
|
||||
|
||||
container.addClass("field-validation-valid").removeClass("field-validation-error");
|
||||
error.removeData("unobtrusiveContainer");
|
||||
|
||||
if (replace) {
|
||||
container.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onReset(event) { // 'this' is the form element
|
||||
var $form = $(this),
|
||||
key = '__jquery_unobtrusive_validation_form_reset';
|
||||
if ($form.data(key)) {
|
||||
return;
|
||||
}
|
||||
// Set a flag that indicates we're currently resetting the form.
|
||||
$form.data(key, true);
|
||||
try {
|
||||
$form.data("validator").resetForm();
|
||||
} finally {
|
||||
$form.removeData(key);
|
||||
}
|
||||
|
||||
$form.find(".validation-summary-errors")
|
||||
.addClass("validation-summary-valid")
|
||||
.removeClass("validation-summary-errors");
|
||||
$form.find(".field-validation-error")
|
||||
.addClass("field-validation-valid")
|
||||
.removeClass("field-validation-error")
|
||||
.removeData("unobtrusiveContainer")
|
||||
.find(">*") // If we were using valmsg-replace, get the underlying error
|
||||
.removeData("unobtrusiveContainer");
|
||||
}
|
||||
|
||||
function validationInfo(form) {
|
||||
var $form = $(form),
|
||||
result = $form.data(data_validation),
|
||||
onResetProxy = $.proxy(onReset, form),
|
||||
defaultOptions = $jQval.unobtrusive.options || {},
|
||||
execInContext = function (name, args) {
|
||||
var func = defaultOptions[name];
|
||||
func && $.isFunction(func) && func.apply(form, args);
|
||||
};
|
||||
|
||||
if (!result) {
|
||||
result = {
|
||||
options: { // options structure passed to jQuery Validate's validate() method
|
||||
errorClass: defaultOptions.errorClass || "input-validation-error",
|
||||
errorElement: defaultOptions.errorElement || "span",
|
||||
errorPlacement: function () {
|
||||
onError.apply(form, arguments);
|
||||
execInContext("errorPlacement", arguments);
|
||||
},
|
||||
invalidHandler: function () {
|
||||
onErrors.apply(form, arguments);
|
||||
execInContext("invalidHandler", arguments);
|
||||
},
|
||||
messages: {},
|
||||
rules: {},
|
||||
success: function () {
|
||||
onSuccess.apply(form, arguments);
|
||||
execInContext("success", arguments);
|
||||
}
|
||||
},
|
||||
attachValidation: function () {
|
||||
$form
|
||||
.off("reset." + data_validation, onResetProxy)
|
||||
.on("reset." + data_validation, onResetProxy)
|
||||
.validate(this.options);
|
||||
},
|
||||
validate: function () { // a validation function that is called by unobtrusive Ajax
|
||||
$form.validate();
|
||||
return $form.valid();
|
||||
}
|
||||
};
|
||||
$form.data(data_validation, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
$jQval.unobtrusive = {
|
||||
adapters: [],
|
||||
|
||||
parseElement: function (element, skipAttach) {
|
||||
/// <summary>
|
||||
/// Parses a single HTML element for unobtrusive validation attributes.
|
||||
/// </summary>
|
||||
/// <param name="element" domElement="true">The HTML element to be parsed.</param>
|
||||
/// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
|
||||
/// validation to the form. If parsing just this single element, you should specify true.
|
||||
/// If parsing several elements, you should specify false, and manually attach the validation
|
||||
/// to the form when you are finished. The default is false.</param>
|
||||
var $element = $(element),
|
||||
form = $element.parents("form")[0],
|
||||
valInfo, rules, messages;
|
||||
|
||||
if (!form) { // Cannot do client-side validation without a form
|
||||
return;
|
||||
}
|
||||
|
||||
valInfo = validationInfo(form);
|
||||
valInfo.options.rules[element.name] = rules = {};
|
||||
valInfo.options.messages[element.name] = messages = {};
|
||||
|
||||
$.each(this.adapters, function () {
|
||||
var prefix = "data-val-" + this.name,
|
||||
message = $element.attr(prefix),
|
||||
paramValues = {};
|
||||
|
||||
if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
|
||||
prefix += "-";
|
||||
|
||||
$.each(this.params, function () {
|
||||
paramValues[this] = $element.attr(prefix + this);
|
||||
});
|
||||
|
||||
this.adapt({
|
||||
element: element,
|
||||
form: form,
|
||||
message: message,
|
||||
params: paramValues,
|
||||
rules: rules,
|
||||
messages: messages
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(rules, { "__dummy__": true });
|
||||
|
||||
if (!skipAttach) {
|
||||
valInfo.attachValidation();
|
||||
}
|
||||
},
|
||||
|
||||
parse: function (selector) {
|
||||
/// <summary>
|
||||
/// Parses all the HTML elements in the specified selector. It looks for input elements decorated
|
||||
/// with the [data-val=true] attribute value and enables validation according to the data-val-*
|
||||
/// attribute values.
|
||||
/// </summary>
|
||||
/// <param name="selector" type="String">Any valid jQuery selector.</param>
|
||||
|
||||
// $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
|
||||
// element with data-val=true
|
||||
var $selector = $(selector),
|
||||
$forms = $selector.parents()
|
||||
.addBack()
|
||||
.filter("form")
|
||||
.add($selector.find("form"))
|
||||
.has("[data-val=true]");
|
||||
|
||||
$selector.find("[data-val=true]").each(function () {
|
||||
$jQval.unobtrusive.parseElement(this, true);
|
||||
});
|
||||
|
||||
$forms.each(function () {
|
||||
var info = validationInfo(this);
|
||||
if (info) {
|
||||
info.attachValidation();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
adapters = $jQval.unobtrusive.adapters;
|
||||
|
||||
adapters.add = function (adapterName, params, fn) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
|
||||
/// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
|
||||
/// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
|
||||
/// mmmm is the parameter name).</param>
|
||||
/// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
|
||||
/// attributes into jQuery Validate rules and/or messages.</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
if (!fn) { // Called with no params, just a function
|
||||
fn = params;
|
||||
params = [];
|
||||
}
|
||||
this.push({ name: adapterName, params: params, adapt: fn });
|
||||
return this;
|
||||
};
|
||||
|
||||
adapters.addBool = function (adapterName, ruleName) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
|
||||
/// the jQuery Validate validation rule has no parameter values.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
|
||||
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
|
||||
/// of adapterName will be used instead.</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
return this.add(adapterName, function (options) {
|
||||
setValidationValues(options, ruleName || adapterName, true);
|
||||
});
|
||||
};
|
||||
|
||||
adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
|
||||
/// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
|
||||
/// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
|
||||
/// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
|
||||
/// have a minimum value.</param>
|
||||
/// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
|
||||
/// have a maximum value.</param>
|
||||
/// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
|
||||
/// have both a minimum and maximum value.</param>
|
||||
/// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
|
||||
/// contains the minimum value. The default is "min".</param>
|
||||
/// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
|
||||
/// contains the maximum value. The default is "max".</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
|
||||
var min = options.params.min,
|
||||
max = options.params.max;
|
||||
|
||||
if (min && max) {
|
||||
setValidationValues(options, minMaxRuleName, [min, max]);
|
||||
}
|
||||
else if (min) {
|
||||
setValidationValues(options, minRuleName, min);
|
||||
}
|
||||
else if (max) {
|
||||
setValidationValues(options, maxRuleName, max);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
adapters.addSingleVal = function (adapterName, attribute, ruleName) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
|
||||
/// the jQuery Validate validation rule has a single value.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
|
||||
/// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
|
||||
/// The default is "val".</param>
|
||||
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
|
||||
/// of adapterName will be used instead.</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
return this.add(adapterName, [attribute || "val"], function (options) {
|
||||
setValidationValues(options, ruleName || adapterName, options.params[attribute]);
|
||||
});
|
||||
};
|
||||
|
||||
$jQval.addMethod("__dummy__", function (value, element, params) {
|
||||
return true;
|
||||
});
|
||||
|
||||
$jQval.addMethod("regex", function (value, element, params) {
|
||||
var match;
|
||||
if (this.optional(element)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
match = new RegExp(params).exec(value);
|
||||
return (match && (match.index === 0) && (match[0].length === value.length));
|
||||
});
|
||||
|
||||
$jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
|
||||
var match;
|
||||
if (nonalphamin) {
|
||||
match = value.match(/\W/g);
|
||||
match = match && match.length >= nonalphamin;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
|
||||
if ($jQval.methods.extension) {
|
||||
adapters.addSingleVal("accept", "mimtype");
|
||||
adapters.addSingleVal("extension", "extension");
|
||||
} else {
|
||||
// for backward compatibility, when the 'extension' validation method does not exist, such as with versions
|
||||
// of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
|
||||
// validating the extension, and ignore mime-type validations as they are not supported.
|
||||
adapters.addSingleVal("extension", "extension", "accept");
|
||||
}
|
||||
|
||||
adapters.addSingleVal("regex", "pattern");
|
||||
adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
|
||||
adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
|
||||
adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
|
||||
adapters.add("equalto", ["other"], function (options) {
|
||||
var prefix = getModelPrefix(options.element.name),
|
||||
other = options.params.other,
|
||||
fullOtherName = appendModelPrefix(other, prefix),
|
||||
element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
|
||||
|
||||
setValidationValues(options, "equalTo", element);
|
||||
});
|
||||
adapters.add("required", function (options) {
|
||||
// jQuery Validate equates "required" with "mandatory" for checkbox elements
|
||||
if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
|
||||
setValidationValues(options, "required", true);
|
||||
}
|
||||
});
|
||||
adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
|
||||
var value = {
|
||||
url: options.params.url,
|
||||
type: options.params.type || "GET",
|
||||
data: {}
|
||||
},
|
||||
prefix = getModelPrefix(options.element.name);
|
||||
|
||||
$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
|
||||
var paramName = appendModelPrefix(fieldName, prefix);
|
||||
value.data[paramName] = function () {
|
||||
var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
|
||||
// For checkboxes and radio buttons, only pick up values from checked fields.
|
||||
if (field.is(":checkbox")) {
|
||||
return field.filter(":checked").val() || field.filter(":hidden").val() || '';
|
||||
}
|
||||
else if (field.is(":radio")) {
|
||||
return field.filter(":checked").val() || '';
|
||||
}
|
||||
return field.val();
|
||||
};
|
||||
});
|
||||
|
||||
setValidationValues(options, "remote", value);
|
||||
});
|
||||
adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
|
||||
if (options.params.min) {
|
||||
setValidationValues(options, "minlength", options.params.min);
|
||||
}
|
||||
if (options.params.nonalphamin) {
|
||||
setValidationValues(options, "nonalphamin", options.params.nonalphamin);
|
||||
}
|
||||
if (options.params.regex) {
|
||||
setValidationValues(options, "regex", options.params.regex);
|
||||
}
|
||||
});
|
||||
adapters.add("fileextensions", ["extensions"], function (options) {
|
||||
setValidationValues(options, "extension", options.params.extensions);
|
||||
});
|
||||
|
||||
$(function () {
|
||||
$jQval.unobtrusive.parse(document);
|
||||
});
|
||||
|
||||
return $jQval.unobtrusive;
|
||||
}));
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright Jörn Zaefferer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,36 @@
|
|||
Copyright JS Foundation and other contributors, https://js.foundation/
|
||||
|
||||
This software consists of voluntary contributions made by many
|
||||
individuals. For exact contribution history, see the revision history
|
||||
available at https://github.com/jquery/jquery
|
||||
|
||||
The following license applies to all parts of this software except as
|
||||
documented below:
|
||||
|
||||
====
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
====
|
||||
|
||||
All files located in the node_modules and external directories are
|
||||
externally maintained libraries used by this software which have their
|
||||
own licenses; we recommend you read them, as their terms may differ from
|
||||
the terms above.
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace iPackage.Core.Web.Extensions
|
||||
{
|
||||
public class DbContextOptionCustomExtensionsInfo : DbContextOptionsExtensionInfo
|
||||
{
|
||||
public DbContextOptionCustomExtensionsInfo(IDbContextOptionsExtension extension) : base(extension)
|
||||
{
|
||||
}
|
||||
|
||||
public override long GetServiceProviderHashCode()
|
||||
{
|
||||
return Extension.GetHashCode();
|
||||
}
|
||||
|
||||
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsDatabaseProvider { get; }
|
||||
public override string LogFragment { get; }
|
||||
}
|
||||
public class DbContextOptionCustomExtensions : IDbContextOptionsExtension
|
||||
{
|
||||
public void ApplyServices(IServiceCollection services)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Validate(IDbContextOptions options)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public DbContextOptionCustomExtensions()
|
||||
{
|
||||
Info = new DbContextOptionCustomExtensionsInfo(this);
|
||||
}
|
||||
public Assembly ProjectAssembly { get; set; }
|
||||
public DbContextOptionsExtensionInfo Info { get; }
|
||||
}
|
||||
public static class ApplicationContextExtensions
|
||||
{
|
||||
public static DbContextOptionsBuilder UseProjectAssembly(this DbContextOptionsBuilder contextOptions, Assembly projectAssembly)
|
||||
{
|
||||
var extension = new DbContextOptionCustomExtensions
|
||||
{
|
||||
ProjectAssembly = projectAssembly
|
||||
};
|
||||
((IDbContextOptionsBuilderInfrastructure)contextOptions).AddOrUpdateExtension(extension);
|
||||
return contextOptions;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Autofac;
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
using iPackage.Core.Web.Repositories;
|
||||
using iPackage.Core.Web.Services;
|
||||
using iPackage.Core.Web.Services.Contracts;
|
||||
using iPackage.Models.Service;
|
||||
using iPackage.Services;
|
||||
using iPackage.Services.Contracts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace iPackage.Core.Web.Extensions
|
||||
{
|
||||
public static class AutoFacConfigExtensions
|
||||
{
|
||||
public static IServiceProvider AddAutoFacContainer(
|
||||
this IServiceCollection serviceCollection,
|
||||
params Assembly[] projectAssembly)
|
||||
{
|
||||
var containerBuilder = new ContainerBuilder();
|
||||
containerBuilder.Populate(serviceCollection);
|
||||
var assembly = projectAssembly;
|
||||
containerBuilder.RegisterAssemblyTypes(assembly)
|
||||
.AssignableTo<IScopedDependency>()
|
||||
.AsImplementedInterfaces()
|
||||
.InstancePerLifetimeScope();
|
||||
|
||||
var container = containerBuilder.Build();
|
||||
return new AutofacServiceProvider(container);
|
||||
}
|
||||
}
|
||||
public static class AutoFacConfigServerExtensions
|
||||
{
|
||||
public static IServiceProvider AddAutoFacServerContainer(this IServiceCollection serviceCollection, params Assembly[] projectAssembly)
|
||||
{
|
||||
var list = projectAssembly.ToList();
|
||||
list.Add(typeof(IRepositoryWrapper).Assembly);
|
||||
list.Add(typeof(IDbService).Assembly);
|
||||
list.Add(typeof(IImageService).Assembly);
|
||||
return serviceCollection.AddAutoFacContainer(list.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using iPackage.Extensions;
|
||||
|
||||
namespace iPackage.Core.Web.Extensions
|
||||
{
|
||||
|
||||
public static class IdentityExtensions
|
||||
{
|
||||
public static string FindFirstValue(this ClaimsIdentity identity, string claimType)
|
||||
{
|
||||
return identity?.FindFirst(claimType)?.Value;
|
||||
}
|
||||
|
||||
public static string FindFirstValue(this IIdentity identity, string claimType)
|
||||
{
|
||||
var claimsIdentity = identity as ClaimsIdentity;
|
||||
return claimsIdentity?.FindFirstValue(claimType);
|
||||
}
|
||||
|
||||
public static string GetUserId(this IIdentity identity)
|
||||
{
|
||||
return identity?.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
}
|
||||
|
||||
public static T GetUserId<T>(this IIdentity identity) where T : IConvertible
|
||||
{
|
||||
var userId = identity?.GetUserId();
|
||||
return userId.HasValue()
|
||||
? (T)Convert.ChangeType(userId, typeof(T), CultureInfo.InvariantCulture)
|
||||
: default(T);
|
||||
}
|
||||
|
||||
public static string GetUserName(this IIdentity identity)
|
||||
{
|
||||
return identity?.FindFirstValue(ClaimTypes.Name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using iPackage.Models.Entity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Pluralize.NET;
|
||||
|
||||
namespace iPackage.Core.Web.Extensions
|
||||
{
|
||||
public class ModelBuilderQueryFilter
|
||||
{
|
||||
public void AddQueryFilterToModelBuilder(ModelBuilder modelBuilder, Type type)
|
||||
{
|
||||
MethodInfo method = this.GetType().GetMethod("RegisterQueryFilter").MakeGenericMethod(type);
|
||||
method.Invoke(this, new object[] { modelBuilder });
|
||||
}
|
||||
|
||||
public void RegisterQueryFilter<TQFilter>(ModelBuilder modelBuilder) where TQFilter : ApiEntity
|
||||
{
|
||||
Type tt = typeof(TQFilter);
|
||||
if (tt.BaseType == typeof(ApiEntity))
|
||||
modelBuilder.Entity<TQFilter>().HasQueryFilter(e => e.IsRemoved == false);
|
||||
}
|
||||
}
|
||||
public static class ModelBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Singularizin table name like Posts to Post or People to Person
|
||||
/// </summary>
|
||||
/// <param name="modelBuilder"></param>
|
||||
public static void AddSingularizingTableNameConvention(this ModelBuilder modelBuilder)
|
||||
{
|
||||
Pluralizer pluralizer = new Pluralizer();
|
||||
foreach (IMutableEntityType entityType in modelBuilder.Model.GetEntityTypes())
|
||||
{
|
||||
string tableName = entityType.GetTableName();
|
||||
entityType.SetTableName(pluralizer.Singularize(tableName));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pluralizing table name like Post to Posts or Person to People
|
||||
/// </summary>
|
||||
/// <param name="modelBuilder"></param>
|
||||
public static void AddPluralizingTableNameConvention(this ModelBuilder modelBuilder)
|
||||
{
|
||||
Pluralizer pluralizer = new Pluralizer();
|
||||
foreach (IMutableEntityType entityType in modelBuilder.Model.GetEntityTypes())
|
||||
{
|
||||
if (entityType.BaseType == null)
|
||||
{
|
||||
string tableName = entityType.GetTableName();
|
||||
entityType.SetTableName(pluralizer.Pluralize(tableName));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set NEWSEQUENTIALID() sql function for all columns named "Id"
|
||||
/// </summary>
|
||||
/// <param name="modelBuilder"></param>
|
||||
/// <param name="mustBeIdentity">Set to true if you want only "Identity" guid fields that named "Id"</param>
|
||||
public static void AddSequentialGuidForIdConvention(this ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.AddDefaultValueSqlConvention("Id", typeof(Guid), "NEWSEQUENTIALID()");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set DefaultValueSql for sepecific property name and type
|
||||
/// </summary>
|
||||
/// <param name="modelBuilder"></param>
|
||||
/// <param name="propertyName">Name of property wants to set DefaultValueSql for</param>
|
||||
/// <param name="propertyType">Type of property wants to set DefaultValueSql for </param>
|
||||
/// <param name="defaultValueSql">DefaultValueSql like "NEWSEQUENTIALID()"</param>
|
||||
public static void AddDefaultValueSqlConvention(this ModelBuilder modelBuilder, string propertyName, Type propertyType, string defaultValueSql)
|
||||
{
|
||||
foreach (IMutableEntityType entityType in modelBuilder.Model.GetEntityTypes())
|
||||
{
|
||||
IMutableProperty property = entityType.GetProperties().SingleOrDefault(p => p.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase));
|
||||
if (property != null && property.ClrType == propertyType)
|
||||
property.SetDefaultValueSql(defaultValueSql);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set DeleteBehavior.Restrict by default for relations
|
||||
/// </summary>
|
||||
/// <param name="modelBuilder"></param>
|
||||
public static void AddRestrictDeleteBehaviorConvention(this ModelBuilder modelBuilder)
|
||||
{
|
||||
IEnumerable<IMutableForeignKey> cascadeFKs = modelBuilder.Model.GetEntityTypes()
|
||||
.SelectMany(t => t.GetForeignKeys())
|
||||
.Where(fk => !fk.IsOwnership && fk.DeleteBehavior == DeleteBehavior.Cascade);
|
||||
foreach (IMutableForeignKey fk in cascadeFKs)
|
||||
fk.DeleteBehavior = DeleteBehavior.Restrict;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dynamicaly load all IEntityTypeConfiguration with Reflection
|
||||
/// </summary>
|
||||
/// <param name="modelBuilder"></param>
|
||||
/// <param name="assemblies">Assemblies contains Entities</param>
|
||||
public static void RegisterEntityTypeConfiguration(this ModelBuilder modelBuilder, params Assembly[] assemblies)
|
||||
{
|
||||
MethodInfo applyGenericMethod = typeof(ModelBuilder).GetMethods().First(m => m.Name == nameof(ModelBuilder.ApplyConfiguration));
|
||||
|
||||
IEnumerable<Type> types = assemblies.SelectMany(a => a.GetExportedTypes())
|
||||
.Where(c => c.IsClass && !c.IsAbstract && c.IsPublic);
|
||||
|
||||
foreach (Type type in types)
|
||||
{
|
||||
foreach (Type iface in type.GetInterfaces())
|
||||
{
|
||||
if (iface.IsConstructedGenericType && iface.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>))
|
||||
{
|
||||
MethodInfo applyConcreteMethod = applyGenericMethod.MakeGenericMethod(iface.GenericTypeArguments[0]);
|
||||
applyConcreteMethod.Invoke(modelBuilder, new object[] { Activator.CreateInstance(type) });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dynamicaly register all Entities that inherit from specific BaseType
|
||||
/// </summary>
|
||||
/// <param name="modelBuilder"></param>
|
||||
/// <param name="baseType">Base type that Entities inherit from this</param>
|
||||
/// <param name="assemblies">Assemblies contains Entities</param>
|
||||
public static void RegisterAllEntities<BaseType>(this ModelBuilder modelBuilder, params Assembly[] assemblies) where BaseType : ApiEntity
|
||||
{
|
||||
IEnumerable<Type> types = assemblies.SelectMany(a => a.GetExportedTypes())
|
||||
.Where(c => c.IsClass && !c.IsAbstract && c.IsPublic && typeof(BaseType).IsAssignableFrom(c));
|
||||
ModelBuilderQueryFilter builderQueryFilter = new ModelBuilderQueryFilter();
|
||||
Pluralizer pluralizer = new Pluralizer();
|
||||
foreach (Type type in types)
|
||||
{
|
||||
modelBuilder.Entity(type);
|
||||
builderQueryFilter.AddQueryFilterToModelBuilder(modelBuilder, type);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace iPackage.Core.Web.Models.Entity
|
||||
{
|
||||
public enum Gender
|
||||
{
|
||||
Mail,
|
||||
Femail
|
||||
}
|
||||
public class Admin : IdentityUser<int>
|
||||
{
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public DateTime BirthDate { get; set; }
|
||||
public string ConnectionId { get; set; }
|
||||
public bool IsConnected { get; set; }
|
||||
public bool IsRemoved { get; set; }
|
||||
public DateTime CreationTime { get; set; }
|
||||
public DateTime RemoveTime { get; set; }
|
||||
|
||||
public Gender Gender { get; set; }
|
||||
[NotMapped]
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using iPackage.Core.Web.Extensions;
|
||||
using iPackage.Models.Entity;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace iPackage.Core.Web.Models.Entity
|
||||
{
|
||||
|
||||
public class ApplicationIdentityContext : IdentityDbContext<Admin, Role, int>
|
||||
{
|
||||
private Assembly _projectAssembly;
|
||||
public ApplicationIdentityContext(DbContextOptions options) : base(options)
|
||||
{
|
||||
_projectAssembly = options.GetExtension<DbContextOptionCustomExtensions>().ProjectAssembly;
|
||||
}
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
var entitiesAssembly = _projectAssembly;
|
||||
modelBuilder.RegisterAllEntities<ApiEntity>(entitiesAssembly);
|
||||
modelBuilder.RegisterEntityTypeConfiguration(entitiesAssembly);
|
||||
modelBuilder.AddRestrictDeleteBehaviorConvention();
|
||||
modelBuilder.AddSequentialGuidForIdConvention();
|
||||
modelBuilder.AddPluralizingTableNameConvention();
|
||||
}
|
||||
public override int SaveChanges()
|
||||
{
|
||||
var entries = ChangeTracker
|
||||
.Entries()
|
||||
.Where(e => e.Entity is ApiEntity && (e.State == EntityState.Added));
|
||||
|
||||
foreach (var entityEntry in entries)
|
||||
{
|
||||
if (entityEntry.State == EntityState.Added)
|
||||
{
|
||||
((ApiEntity)entityEntry.Entity).CreationTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
return base.SaveChanges();
|
||||
}
|
||||
|
||||
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
var entries = ChangeTracker
|
||||
.Entries()
|
||||
.Where(e => e.Entity is ApiEntity && (e.State == EntityState.Added));
|
||||
|
||||
foreach (var entityEntry in entries)
|
||||
{
|
||||
if (entityEntry.State == EntityState.Added)
|
||||
{
|
||||
((ApiEntity)entityEntry.Entity).CreationTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
return base.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public class ApplicationIdentityContext<TAdmin,TRole,TKey> : IdentityDbContext<TAdmin, TRole, TKey>
|
||||
where TAdmin : IdentityUser<TKey>
|
||||
where TKey : IEquatable<TKey>
|
||||
where TRole : IdentityRole<TKey>
|
||||
{
|
||||
private Assembly _projectAssembly;
|
||||
public ApplicationIdentityContext(DbContextOptions options) : base(options)
|
||||
{
|
||||
_projectAssembly = options.GetExtension<DbContextOptionCustomExtensions>().ProjectAssembly;
|
||||
}
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
var entitiesAssembly = _projectAssembly;
|
||||
modelBuilder.RegisterAllEntities<ApiEntity>(entitiesAssembly);
|
||||
modelBuilder.RegisterEntityTypeConfiguration(entitiesAssembly);
|
||||
modelBuilder.AddRestrictDeleteBehaviorConvention();
|
||||
modelBuilder.AddSequentialGuidForIdConvention();
|
||||
modelBuilder.AddPluralizingTableNameConvention();
|
||||
}
|
||||
public override int SaveChanges()
|
||||
{
|
||||
var entries = ChangeTracker
|
||||
.Entries()
|
||||
.Where(e => e.Entity is ApiEntity && (e.State == EntityState.Added));
|
||||
|
||||
foreach (var entityEntry in entries)
|
||||
{
|
||||
if (entityEntry.State == EntityState.Added)
|
||||
{
|
||||
((ApiEntity)entityEntry.Entity).CreationTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
return base.SaveChanges();
|
||||
}
|
||||
|
||||
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
var entries = ChangeTracker
|
||||
.Entries()
|
||||
.Where(e => e.Entity is ApiEntity && (e.State == EntityState.Added));
|
||||
|
||||
foreach (var entityEntry in entries)
|
||||
{
|
||||
if (entityEntry.State == EntityState.Added)
|
||||
{
|
||||
((ApiEntity)entityEntry.Entity).CreationTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
return base.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public class ApplicationContext : DbContext
|
||||
{
|
||||
private Assembly _projectAssembly;
|
||||
public ApplicationContext(DbContextOptions options) : base(options)
|
||||
{
|
||||
_projectAssembly = options.GetExtension<DbContextOptionCustomExtensions>().ProjectAssembly;
|
||||
}
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
var entitiesAssembly = _projectAssembly;
|
||||
modelBuilder.RegisterAllEntities<ApiEntity>(entitiesAssembly);
|
||||
modelBuilder.RegisterEntityTypeConfiguration(entitiesAssembly);
|
||||
modelBuilder.AddRestrictDeleteBehaviorConvention();
|
||||
modelBuilder.AddSequentialGuidForIdConvention();
|
||||
modelBuilder.AddPluralizingTableNameConvention();
|
||||
}
|
||||
public override int SaveChanges()
|
||||
{
|
||||
var entries = ChangeTracker
|
||||
.Entries()
|
||||
.Where(e => e.Entity is ApiEntity && (e.State == EntityState.Added));
|
||||
|
||||
foreach (var entityEntry in entries)
|
||||
{
|
||||
if (entityEntry.State == EntityState.Added)
|
||||
{
|
||||
((ApiEntity)entityEntry.Entity).CreationTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
return base.SaveChanges();
|
||||
}
|
||||
|
||||
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
var entries = ChangeTracker
|
||||
.Entries()
|
||||
.Where(e => e.Entity is ApiEntity && (e.State == EntityState.Added));
|
||||
|
||||
foreach (var entityEntry in entries)
|
||||
{
|
||||
if (entityEntry.State == EntityState.Added)
|
||||
{
|
||||
((ApiEntity)entityEntry.Entity).CreationTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
return base.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace iPackage.Core.Web.Models.Entity
|
||||
{
|
||||
public class Role : IdentityRole<int>
|
||||
{
|
||||
[Required]
|
||||
public string Description { get; set; }
|
||||
[NotMapped]
|
||||
public List<Claim> Claims { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using iPackage.Models.Api;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace iPackage.Core.Web.Models.Filter
|
||||
{
|
||||
|
||||
public class ApiResultFilterAttribute : ActionFilterAttribute
|
||||
{
|
||||
public override void OnResultExecuting(ResultExecutingContext context)
|
||||
{
|
||||
if (context.Result is OkObjectResult okObjectResult)
|
||||
{
|
||||
var apiResult = new ApiResult<object>(true, ApiResultStatusCode.Success, okObjectResult.Value);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = okObjectResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is OkResult okResult)
|
||||
{
|
||||
var apiResult = new ApiResult(true, ApiResultStatusCode.Success);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = okResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is BadRequestResult badRequestResult)
|
||||
{
|
||||
var apiResult = new ApiResult(false, ApiResultStatusCode.BadRequest);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = badRequestResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is BadRequestObjectResult badRequestObjectResult)
|
||||
{
|
||||
var message = badRequestObjectResult.Value.ToString();
|
||||
|
||||
if (badRequestObjectResult.Value is SerializableError errors)
|
||||
{
|
||||
var errorMessages = errors.SelectMany(p => (string[])p.Value).Distinct();
|
||||
message = string.Join(" | ", errorMessages);
|
||||
}
|
||||
if (badRequestObjectResult.Value is ValidationProblemDetails problemDetails)
|
||||
{
|
||||
var errorMessages = problemDetails.Errors.Values.SelectMany(v => v);
|
||||
message = string.Join(" | ", errorMessages);
|
||||
}
|
||||
var apiResult = new ApiResult(false, ApiResultStatusCode.BadRequest, message);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = badRequestObjectResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is ContentResult contentResult)
|
||||
{
|
||||
var apiResult = new ApiResult(true, ApiResultStatusCode.Success, contentResult.Content);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = contentResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is NotFoundResult notFoundResult)
|
||||
{
|
||||
var apiResult = new ApiResult(false, ApiResultStatusCode.NotFound);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = notFoundResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is NotFoundObjectResult notFoundObjectResult)
|
||||
{
|
||||
var apiResult = new ApiResult<object>(false, ApiResultStatusCode.NotFound, notFoundObjectResult.Value);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = notFoundObjectResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is ObjectResult objectResult && objectResult.StatusCode == null
|
||||
&& !(objectResult.Value is ApiResult))
|
||||
{
|
||||
var apiResult = new ApiResult<object>(true, ApiResultStatusCode.Success, objectResult.Value);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = objectResult.StatusCode };
|
||||
}
|
||||
|
||||
base.OnResultExecuting(context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace iPackage.Core.Web.Models.Settings
|
||||
{
|
||||
public class JwtSettings
|
||||
{
|
||||
public string SecretKey { get; set; }
|
||||
public string Issuer { get; set; }
|
||||
public string Audience { get; set; }
|
||||
public int ExpireAddDay { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace iPackage.Core.Web.Models.Settings
|
||||
{
|
||||
public class RootAdmin
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string RoleName { get; set; }
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public string Phone { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace iPackage.Core.Web.Models.Settings
|
||||
{
|
||||
public class ServerSettings
|
||||
{
|
||||
public bool Seeded { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace iPackage.Core.Web.Models.Settings
|
||||
{
|
||||
public class SiteSettings
|
||||
{
|
||||
public JwtSettings JwtSettings { get; set; }
|
||||
public string BaseUrl { get; set; }
|
||||
public bool Published { get; set; }
|
||||
public RootAdmin RootAdmin { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using iPackage.Core.Web.Models.Entity;
|
||||
using iPackage.Extensions;
|
||||
using iPackage.Models.Entity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace iPackage.Core.Web.Repositories
|
||||
{
|
||||
|
||||
|
||||
public class BaseRepository<T> : IBaseRepository<T>
|
||||
where T : class, IApiEntity
|
||||
{
|
||||
protected readonly ApplicationIdentityContext DbContext;
|
||||
public DbSet<T> Entities { get; }
|
||||
public virtual IQueryable<T> Table => Entities.Where(e => e.IsRemoved == false);
|
||||
public virtual IQueryable<T> TableNoTracking => Entities.AsNoTracking().Where(e => e.IsRemoved == false);
|
||||
|
||||
public BaseRepository(ApplicationIdentityContext dbContext)
|
||||
{
|
||||
DbContext = dbContext;
|
||||
Entities = DbContext.Set<T>(); // City => Cities
|
||||
}
|
||||
|
||||
#region Async Method
|
||||
public virtual ValueTask<T> GetByIdAsync(CancellationToken cancellationToken, params object[] ids)
|
||||
{
|
||||
return Entities.FindAsync(ids, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task AddAsync(T entity, CancellationToken cancellationToken, bool saveNow = true)
|
||||
{
|
||||
Assert.NotNull(entity, nameof(entity));
|
||||
entity.CreationTime = DateTime.Now;
|
||||
await Entities.AddAsync(entity, cancellationToken).ConfigureAwait(false);
|
||||
if (saveNow)
|
||||
await DbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public virtual async Task AddRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken, bool saveNow = true)
|
||||
{
|
||||
Assert.NotNull(entities, nameof(entities));
|
||||
await Entities.AddRangeAsync(entities, cancellationToken).ConfigureAwait(false);
|
||||
if (saveNow)
|
||||
await DbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public virtual async Task UpdateAsync(T entity, CancellationToken cancellationToken, bool saveNow = true)
|
||||
{
|
||||
Assert.NotNull(entity, nameof(entity));
|
||||
//DbContext.Entry(entity).State = EntityState.Detached;
|
||||
//DbContext.Entry(entity).State = EntityState.Modified;
|
||||
DbContext.Update(entity);
|
||||
//DbContext.Entry(entity).CurrentValues.SetValues(entity);
|
||||
if (saveNow)
|
||||
await DbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task UpdateRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken, bool saveNow = true)
|
||||
{
|
||||
Assert.NotNull(entities, nameof(entities));
|
||||
Entities.UpdateRange(entities);
|
||||
if (saveNow)
|
||||
await DbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task DeleteAsync(T entity, CancellationToken cancellationToken, bool saveNow = true)
|
||||
{
|
||||
Assert.NotNull(entity, nameof(entity));
|
||||
entity.IsRemoved = true;
|
||||
Entities.Update(entity);
|
||||
if (saveNow)
|
||||
await DbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task HardDeleteAsync(T entity, CancellationToken cancellationToken, bool saveNow = true)
|
||||
{
|
||||
Assert.NotNull(entity, nameof(entity));
|
||||
Entities.Remove(entity);
|
||||
if (saveNow)
|
||||
await DbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task DeleteRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken, bool saveNow = true)
|
||||
{
|
||||
Assert.NotNull(entities, nameof(entities));
|
||||
foreach (var apiEntity in entities)
|
||||
{
|
||||
apiEntity.IsRemoved = true;
|
||||
Entities.Update(apiEntity);
|
||||
}
|
||||
if (saveNow)
|
||||
await DbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Sync Methods
|
||||
public virtual T GetById(params object[] ids)
|
||||
{
|
||||
var ent = Entities.Find(ids);
|
||||
Detach(ent);
|
||||
return ent;
|
||||
}
|
||||
|
||||
public virtual void Add(T entity, bool saveNow = true)
|
||||
{
|
||||
Assert.NotNull(entity, nameof(entity));
|
||||
Entities.Add(entity);
|
||||
if (saveNow)
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public virtual void AddRange(IEnumerable<T> entities, bool saveNow = true)
|
||||
{
|
||||
Assert.NotNull(entities, nameof(entities));
|
||||
Entities.AddRange(entities);
|
||||
if (saveNow)
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public virtual void Update(T entity, bool saveNow = true)
|
||||
{
|
||||
Assert.NotNull(entity, nameof(entity));
|
||||
Detach(entity);
|
||||
Entities.Update(entity);
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public virtual void UpdateRange(IEnumerable<T> entities, bool saveNow = true)
|
||||
{
|
||||
Assert.NotNull(entities, nameof(entities));
|
||||
Entities.UpdateRange(entities);
|
||||
if (saveNow)
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public virtual void Delete(T entity, bool saveNow = true)
|
||||
{
|
||||
Assert.NotNull(entity, nameof(entity));
|
||||
Entities.Remove(entity);
|
||||
if (saveNow)
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public virtual void DeleteRange(IEnumerable<T> entities, bool saveNow = true)
|
||||
{
|
||||
Assert.NotNull(entities, nameof(entities));
|
||||
Entities.RemoveRange(entities);
|
||||
if (saveNow)
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Attach & Detach
|
||||
public virtual void Detach(T entity)
|
||||
{
|
||||
Assert.NotNull(entity, nameof(entity));
|
||||
var entry = DbContext.Entry(entity);
|
||||
if (entry != null)
|
||||
entry.State = EntityState.Detached;
|
||||
}
|
||||
|
||||
public virtual void Attach(T entity)
|
||||
{
|
||||
Assert.NotNull(entity, nameof(entity));
|
||||
if (DbContext.Entry(entity).State == EntityState.Detached)
|
||||
Entities.Attach(entity);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Explicit Loading
|
||||
public virtual async Task LoadCollectionAsync<TProperty>(T entity, Expression<Func<T, IEnumerable<TProperty>>> collectionProperty, CancellationToken cancellationToken)
|
||||
where TProperty : class
|
||||
{
|
||||
Attach(entity);
|
||||
|
||||
var collection = DbContext.Entry(entity).Collection(collectionProperty);
|
||||
if (!collection.IsLoaded)
|
||||
await collection.LoadAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public virtual void LoadCollection<TProperty>(T entity, Expression<Func<T, IEnumerable<TProperty>>> collectionProperty)
|
||||
where TProperty : class
|
||||
{
|
||||
Attach(entity);
|
||||
var collection = DbContext.Entry(entity).Collection(collectionProperty);
|
||||
if (!collection.IsLoaded)
|
||||
collection.Load();
|
||||
}
|
||||
|
||||
public virtual async Task LoadReferenceAsync<TProperty>(T entity, Expression<Func<T, TProperty>> referenceProperty, CancellationToken cancellationToken)
|
||||
where TProperty : class
|
||||
{
|
||||
Attach(entity);
|
||||
var reference = DbContext.Entry(entity).Reference(referenceProperty);
|
||||
if (!reference.IsLoaded)
|
||||
await reference.LoadAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public virtual void LoadReference<TProperty>(T entity, Expression<Func<T, TProperty>> referenceProperty)
|
||||
where TProperty : class
|
||||
{
|
||||
Attach(entity);
|
||||
var reference = DbContext.Entry(entity).Reference(referenceProperty);
|
||||
if (!reference.IsLoaded)
|
||||
reference.Load();
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using iPackage.Models.Entity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace iPackage.Core.Web.Repositories
|
||||
{
|
||||
|
||||
public interface IBaseRepository<T> where T : class, IApiEntity
|
||||
{
|
||||
DbSet<T> Entities { get; }
|
||||
IQueryable<T> Table { get; }
|
||||
IQueryable<T> TableNoTracking { get; }
|
||||
|
||||
void Add(T entity, bool saveNow = true);
|
||||
Task AddAsync(T entity, CancellationToken cancellationToken, bool saveNow = true);
|
||||
void AddRange(IEnumerable<T> entities, bool saveNow = true);
|
||||
Task AddRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken, bool saveNow = true);
|
||||
void Attach(T entity);
|
||||
void Delete(T entity, bool saveNow = true);
|
||||
Task DeleteAsync(T entity, CancellationToken cancellationToken, bool saveNow = true);
|
||||
Task HardDeleteAsync(T entity, CancellationToken cancellationToken, bool saveNow = true);
|
||||
void DeleteRange(IEnumerable<T> entities, bool saveNow = true);
|
||||
Task DeleteRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken, bool saveNow = true);
|
||||
void Detach(T entity);
|
||||
T GetById(params object[] ids);
|
||||
ValueTask<T> GetByIdAsync(CancellationToken cancellationToken, params object[] ids);
|
||||
void LoadCollection<TProperty>(T entity, Expression<Func<T, IEnumerable<TProperty>>> collectionProperty) where TProperty : class;
|
||||
Task LoadCollectionAsync<TProperty>(T entity, Expression<Func<T, IEnumerable<TProperty>>> collectionProperty, CancellationToken cancellationToken) where TProperty : class;
|
||||
void LoadReference<TProperty>(T entity, Expression<Func<T, TProperty>> referenceProperty) where TProperty : class;
|
||||
Task LoadReferenceAsync<TProperty>(T entity, Expression<Func<T, TProperty>> referenceProperty, CancellationToken cancellationToken) where TProperty : class;
|
||||
void Update(T entity, bool saveNow = true);
|
||||
Task UpdateAsync(T entity, CancellationToken cancellationToken, bool saveNow = true);
|
||||
void UpdateRange(IEnumerable<T> entities, bool saveNow = true);
|
||||
Task UpdateRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken, bool saveNow = true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using iPackage.Models.Entity;
|
||||
|
||||
namespace iPackage.Core.Web.Repositories
|
||||
{
|
||||
public interface IRepositoryWrapper
|
||||
{
|
||||
IBaseRepository<T> SetRepository<T>() where T : ApiEntity;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using iPackage.Core.Web.Models.Entity;
|
||||
using iPackage.Models.Entity;
|
||||
using iPackage.Models.Service;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace iPackage.Core.Web.Repositories
|
||||
{
|
||||
public class RepositoryWrapper : IRepositoryWrapper, IScopedDependency
|
||||
{
|
||||
private readonly ApplicationIdentityContext _context;
|
||||
public RepositoryWrapper(ApplicationIdentityContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
public IBaseRepository<T> SetRepository<T>() where T : ApiEntity
|
||||
{
|
||||
IBaseRepository<T> repository = new BaseRepository<T>(_context);
|
||||
return repository;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using iPackage.Core.Web.Services.Contracts;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace iPackage.Core.Web.Services
|
||||
{
|
||||
public class CacheService : ICacheService
|
||||
{
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
|
||||
public CacheService(IMemoryCache memoryCache)
|
||||
{
|
||||
_memoryCache = memoryCache;
|
||||
}
|
||||
public TCache Get<TCache>(string cacheName = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(cacheName))
|
||||
cacheName = (typeof(TCache).Name);
|
||||
var cache = _memoryCache.Get<TCache>(cacheName);
|
||||
return cache;
|
||||
}
|
||||
|
||||
public void Set(object cache, string cacheName = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(cacheName))
|
||||
cacheName = cache.GetType().Name;
|
||||
_memoryCache.Set(cacheName, cache);
|
||||
}
|
||||
|
||||
public void Delete<TCache>(string cacheName = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(cacheName))
|
||||
cacheName = (typeof(TCache)).Name;
|
||||
_memoryCache.Remove(cacheName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using iPackage.Models.Service;
|
||||
|
||||
namespace iPackage.Core.Web.Services.Contracts
|
||||
{
|
||||
public interface ICacheService : IScopedDependency
|
||||
{
|
||||
TCache Get<TCache>(string cacheName = null);
|
||||
void Set(object cache, string cacheName = null);
|
||||
void Delete<TCache>(string cacheName = null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using iPackage.Models.Service;
|
||||
|
||||
namespace iPackage.Core.Web.Services.Contracts
|
||||
{
|
||||
public interface IDbService : IScopedDependency
|
||||
{
|
||||
void Initialize();
|
||||
string CreateBackUp();
|
||||
List<string> GetBackUps();
|
||||
bool RestoreBackUp(string backUpId);
|
||||
bool RemoveBackUp(string backUpId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using iPackage.Core.Web.Models.Entity;
|
||||
using iPackage.Models.Api;
|
||||
using iPackage.Models.Service;
|
||||
|
||||
namespace iPackage.Core.Web.Services.Contracts
|
||||
{
|
||||
public interface IJWTService : IScopedDependency
|
||||
{
|
||||
Task<AccessToken> Generate(Admin user);
|
||||
Task<AccessToken<TUser>> Generate<TUser>(Admin user);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using iPackage.Models.Dto;
|
||||
using iPackage.Models.Entity;
|
||||
using iPackage.Models.Service;
|
||||
using iPackage.Models.Util;
|
||||
|
||||
namespace iPackage.Core.Web.Services.Contracts
|
||||
{
|
||||
public interface IReportService : IScopedDependency
|
||||
{
|
||||
Task<ReportResult> CrudDataBaseReportTask<T>(ReportRequest request) where T : ApiEntity;
|
||||
|
||||
Task<ReportResult> CrudDataBaseDtoReportTask<T, TDto>(ReportRequest request)
|
||||
where T : ApiEntity, new()
|
||||
where TDto : BaseDto<TDto, T>, new();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using iPackage.Core.Web.Models.Entity;
|
||||
using iPackage.Core.Web.Models.Settings;
|
||||
using iPackage.Core.Web.Services.Contracts;
|
||||
using iPackage.Extensions;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace iPackage.Core.Web.Services
|
||||
{
|
||||
|
||||
public class DbService : IDbService
|
||||
{
|
||||
private readonly ApplicationIdentityContext _context;
|
||||
private readonly IOptionsSnapshot<SiteSettings> _adminUserSeedOptions;
|
||||
|
||||
public DbService(
|
||||
ApplicationIdentityContext context,
|
||||
IOptionsSnapshot<SiteSettings> adminUserSeedOptions)
|
||||
{
|
||||
_context = context;
|
||||
_adminUserSeedOptions = adminUserSeedOptions;
|
||||
}
|
||||
public void Initialize()
|
||||
{
|
||||
_context.Database.EnsureCreated();
|
||||
_context.Database.Migrate();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public string CreateBackUp()
|
||||
{
|
||||
var backUpName = $"{StringExtensions.GetId()}_{DateTime.Now.ToString(" yyyy-MM-dd HH-mm-ss")}.bak";
|
||||
var path = $"{Directory.GetCurrentDirectory()}/wwwroot/BackUps/{backUpName}";
|
||||
string commandText = $@"BACKUP DATABASE [iGarsonDB] TO DISK = N'{path}' WITH NOFORMAT, INIT, NAME = N'iGarsonDB-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10";
|
||||
|
||||
SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder
|
||||
{
|
||||
DataSource = ".",
|
||||
InitialCatalog = "iGarsonDB",
|
||||
IntegratedSecurity = true
|
||||
};
|
||||
using (SqlConnection connection = new SqlConnection(connectionStringBuilder.ConnectionString))
|
||||
{
|
||||
connection.Open();
|
||||
using (SqlCommand command = connection.CreateCommand())
|
||||
{
|
||||
command.CommandText = commandText;
|
||||
command.CommandType = CommandType.Text;
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
return backUpName;
|
||||
}
|
||||
|
||||
public List<string> GetBackUps()
|
||||
{
|
||||
var files = Directory.GetFiles($"{Directory.GetCurrentDirectory()}/wwwroot/BackUps");
|
||||
return files.Select(f => f.Split('\\').Last()).ToList();
|
||||
}
|
||||
|
||||
public bool RestoreBackUp(string backUpId)
|
||||
{
|
||||
var files = Directory.GetFiles($"{Directory.GetCurrentDirectory()}/wwwroot/BackUps");
|
||||
string backUpName = string.Empty;
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (file.Contains(backUpId))
|
||||
backUpName = file;
|
||||
}
|
||||
if (string.IsNullOrEmpty(backUpName))
|
||||
return false;
|
||||
|
||||
var databaseName = "iGarsonDB";
|
||||
var path = backUpName;
|
||||
string commandText = $@"USE [master];
|
||||
ALTER DATABASE [{databaseName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
|
||||
RESTORE DATABASE [{databaseName}] FROM DISK = N'{path}' WITH FILE = 1, NOUNLOAD, REPLACE, STATS = 5;
|
||||
ALTER DATABASE [{databaseName}] SET MULTI_USER;";
|
||||
|
||||
SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder
|
||||
{
|
||||
DataSource = ".",
|
||||
InitialCatalog = "iGarsonDB",
|
||||
IntegratedSecurity = true
|
||||
};
|
||||
using (SqlConnection connection = new SqlConnection(connectionStringBuilder.ConnectionString))
|
||||
{
|
||||
connection.Open();
|
||||
using (SqlCommand command = connection.CreateCommand())
|
||||
{
|
||||
command.CommandText = commandText;
|
||||
command.CommandType = CommandType.Text;
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RemoveBackUp(string backUpId)
|
||||
{
|
||||
var files = Directory.GetFiles($"{Directory.GetCurrentDirectory()}/wwwroot/BackUps");
|
||||
string backUpName = string.Empty;
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (file.Contains(backUpId))
|
||||
backUpName = file;
|
||||
}
|
||||
if (string.IsNullOrEmpty(backUpName))
|
||||
return false;
|
||||
var path = backUpName;
|
||||
File.Delete(path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using iPackage.Core.Web.Models.Entity;
|
||||
using iPackage.Core.Web.Models.Settings;
|
||||
using iPackage.Core.Web.Services.Contracts;
|
||||
using iPackage.Models.Api;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace iPackage.Core.Web.Services
|
||||
{
|
||||
|
||||
public class JWTService : IJWTService
|
||||
{
|
||||
private readonly SignInManager<Admin> _signInManager;
|
||||
private readonly SiteSettings _siteSettings;
|
||||
|
||||
public JWTService(
|
||||
IOptionsSnapshot<SiteSettings> siteSettings,
|
||||
SignInManager<Admin> signInManager)
|
||||
{
|
||||
_signInManager = signInManager;
|
||||
_siteSettings = siteSettings.Value;
|
||||
}
|
||||
|
||||
public async Task<AccessToken> Generate(Admin user)
|
||||
{
|
||||
var secretKey = Encoding.UTF8.GetBytes(_siteSettings.JwtSettings.SecretKey);
|
||||
var signingCredintial = new SigningCredentials(new SymmetricSecurityKey(secretKey),
|
||||
SecurityAlgorithms.HmacSha512Signature);
|
||||
var claims = await GetClaims(user);
|
||||
var desctiptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Issuer = _siteSettings.JwtSettings.Issuer,
|
||||
Audience = _siteSettings.JwtSettings.Audience,
|
||||
IssuedAt = DateTime.Now,
|
||||
NotBefore = DateTime.Now,
|
||||
Expires = DateTime.Now.AddDays(_siteSettings.JwtSettings.ExpireAddDay),
|
||||
SigningCredentials = signingCredintial,
|
||||
Subject = new ClaimsIdentity(claims)
|
||||
};
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
return new AccessToken(handler.CreateJwtSecurityToken(desctiptor));
|
||||
}
|
||||
|
||||
public async Task<AccessToken<TUser>> Generate<TUser>(Admin user)
|
||||
{
|
||||
var secretKey = Encoding.UTF8.GetBytes(_siteSettings.JwtSettings.SecretKey);
|
||||
var signingCredintial = new SigningCredentials(new SymmetricSecurityKey(secretKey),
|
||||
SecurityAlgorithms.HmacSha512Signature);
|
||||
var claims = await GetClaims(user);
|
||||
var desctiptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Issuer = _siteSettings.JwtSettings.Issuer,
|
||||
Audience = _siteSettings.JwtSettings.Audience,
|
||||
IssuedAt = DateTime.Now,
|
||||
NotBefore = DateTime.Now,
|
||||
Expires = DateTime.Now.AddDays(_siteSettings.JwtSettings.ExpireAddDay),
|
||||
SigningCredentials = signingCredintial,
|
||||
Subject = new ClaimsIdentity(claims)
|
||||
};
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
return new AccessToken<TUser>(handler.CreateJwtSecurityToken(desctiptor));
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<Claim>> GetClaims(Admin user)
|
||||
{
|
||||
var claims = (await _signInManager.ClaimsFactory.CreateAsync(user)).Claims.ToList();
|
||||
claims.Add(new Claim(ClaimTypes.Gender, user.Gender == 0 ? "Femail" : "Mail"));
|
||||
return claims;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper.QueryableExtensions;
|
||||
using iPackage.Core.Web.Repositories;
|
||||
using iPackage.Core.Web.Services.Contracts;
|
||||
using iPackage.Extensions;
|
||||
using iPackage.Models.Dto;
|
||||
using iPackage.Models.Entity;
|
||||
using iPackage.Models.Util;
|
||||
using MD.PersianDateTime.Standard;
|
||||
|
||||
namespace iPackage.Core.Web.Services
|
||||
{
|
||||
|
||||
public class ReportService : IReportService
|
||||
{
|
||||
private readonly IRepositoryWrapper _repositoryWrapper;
|
||||
|
||||
public ReportService(IRepositoryWrapper repositoryWrapper)
|
||||
{
|
||||
_repositoryWrapper = repositoryWrapper;
|
||||
}
|
||||
|
||||
|
||||
public async Task<ReportResult> CrudDataBaseReportTask<T>(ReportRequest request) where T : ApiEntity
|
||||
{
|
||||
var table = _repositoryWrapper.SetRepository<T>().TableNoTracking;
|
||||
switch (request.ReportType)
|
||||
{
|
||||
case ReportType.ByDate:
|
||||
table = table.Where(t => t.CreationTime.Date >= request.FromDateTime.Date && t.CreationTime.Date <= request.ToDateTime.Date);
|
||||
break;
|
||||
case ReportType.ByValue:
|
||||
throw new Exception("درخواست گزارش صحیح نیست تنها مقدور به درخواست تاریخی هستید");
|
||||
default:
|
||||
throw new Exception("درخواست گزارش صحیح نیست تنها مقدور به درخواست تاریخی هستید");
|
||||
}
|
||||
var result = await CreateReportFromDates<T>(table);
|
||||
return result;
|
||||
}
|
||||
public async Task<ReportResult> CrudDataBaseDtoReportTask<T, TDto>(ReportRequest request)
|
||||
where T : ApiEntity, new()
|
||||
where TDto : BaseDto<TDto, T>, new()
|
||||
{
|
||||
var table = _repositoryWrapper.SetRepository<T>().TableNoTracking;
|
||||
switch (request.ReportType)
|
||||
{
|
||||
case ReportType.ByDate:
|
||||
table = table.Where(t => t.CreationTime.Date >= request.FromDateTime.Date && t.CreationTime.Date <= request.ToDateTime.Date);
|
||||
break;
|
||||
case ReportType.ByValue:
|
||||
throw new Exception("درخواست گزارش صحیح نیست تنها مقدور به درخواست تاریخی هستید");
|
||||
default:
|
||||
throw new Exception("درخواست گزارش صحیح نیست تنها مقدور به درخواست تاریخی هستید");
|
||||
}
|
||||
var result = await CreateReportFromDates<TDto>(table.ProjectTo<TDto>());
|
||||
return result;
|
||||
}
|
||||
private async Task<ReportResult> CreateReportFromDates<T>(IQueryable<T> table)
|
||||
{
|
||||
ReportResult result = new ReportResult();
|
||||
|
||||
var baseObj = Activator.CreateInstance<T>();
|
||||
var baseProperteis = baseObj.GetType().GetProperties();
|
||||
var headerRow = new ReportRow();
|
||||
|
||||
|
||||
foreach (var peroperty in baseProperteis)
|
||||
{
|
||||
if (peroperty.GetCustomAttributes(typeof(DisplayAttribute)).FirstOrDefault() == null)
|
||||
continue;
|
||||
var atts = peroperty.CustomAttributes;
|
||||
if (peroperty.GetType() != typeof(IList) && peroperty.GetType() != typeof(ICollection))
|
||||
headerRow.Cells.Add(peroperty.GetPropertyDisplayName());
|
||||
}
|
||||
result.Rows.Add(headerRow);
|
||||
|
||||
if (table is IQueryable queryTable)
|
||||
{
|
||||
foreach (var query in queryTable)
|
||||
{
|
||||
var row = new ReportRow();
|
||||
var peroperties = query.GetType().GetProperties();
|
||||
foreach (var peroperty in peroperties)
|
||||
{
|
||||
if (peroperty.GetCustomAttributes(typeof(DisplayAttribute)).FirstOrDefault() == null)
|
||||
continue;
|
||||
if (peroperty.GetValue(query) is bool)
|
||||
row.Cells.Add((bool)peroperty.GetValue(query) ? "بلی" : "خیر");
|
||||
else if (peroperty.GetValue(query) is DateTime)
|
||||
{
|
||||
var datetime = new PersianDateTime((DateTime)peroperty.GetValue(query));
|
||||
row.Cells.Add(datetime.ToString());
|
||||
}
|
||||
else if (peroperty.GetValue(query) is Enum)
|
||||
{
|
||||
var enumDisplay = EnumExtensions.ToDisplay((Enum)peroperty.GetValue(query));
|
||||
row.Cells.Add(enumDisplay);
|
||||
}
|
||||
else if (peroperty.GetType() != typeof(IList) && peroperty.GetType() != typeof(ICollection))
|
||||
row.Cells.Add(peroperty.GetValue(query)?.ToString());
|
||||
}
|
||||
result.Rows.Add(row);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using iPackage.Core.Web.Services.Contracts;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace iPackage.Core.Web.WebFramework.Configurations
|
||||
{
|
||||
public static class AppConfigExtensions
|
||||
{
|
||||
public static async void UseDbInitializer(this IApplicationBuilder app)
|
||||
{
|
||||
var scopeFactory = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>();
|
||||
using (var scope = scopeFactory.CreateScope())
|
||||
{
|
||||
var identityDbInitialize = scope.ServiceProvider.GetService<IDbService>();
|
||||
identityDbInitialize.Initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using iPackage.Core.Web.Extensions;
|
||||
using iPackage.Core.Web.Models.Entity;
|
||||
using iPackage.Core.Web.Models.Settings;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace iPackage.Core.Web.WebFramework.Configurations
|
||||
{
|
||||
|
||||
public static class ServiceConfigExtensions
|
||||
{
|
||||
public static void AddJwtCustomAuthentication(this IServiceCollection serviceCollection, JwtSettings jwtSettings)
|
||||
{
|
||||
serviceCollection.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
var secretKey = Encoding.UTF8.GetBytes(jwtSettings.SecretKey);
|
||||
var validateParammetrs = new TokenValidationParameters
|
||||
{
|
||||
ClockSkew = TimeSpan.Zero,
|
||||
RequireSignedTokens = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(secretKey),
|
||||
RequireExpirationTime = true,
|
||||
ValidateLifetime = true,
|
||||
ValidateAudience = true,
|
||||
ValidAudience = jwtSettings.Audience,
|
||||
ValidateIssuer = true,
|
||||
ValidIssuer = jwtSettings.Issuer
|
||||
|
||||
};
|
||||
options.RequireHttpsMetadata = true;
|
||||
options.SaveToken = true;
|
||||
options.TokenValidationParameters = validateParammetrs;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public static void AddCustomIdentity<TApplicationContext>(this IServiceCollection serviceCollection) where TApplicationContext : DbContext
|
||||
{
|
||||
serviceCollection.AddIdentity<Admin, Role>(options =>
|
||||
{
|
||||
options.Password.RequireLowercase = false;
|
||||
options.Password.RequireUppercase = false;
|
||||
options.Password.RequireDigit = false;
|
||||
options.Password.RequireNonAlphanumeric = false;
|
||||
options.User.RequireUniqueEmail = false;
|
||||
}).AddEntityFrameworkStores<TApplicationContext>().AddDefaultTokenProviders();
|
||||
}
|
||||
|
||||
public static void AddCustomApiVersioning(this IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddApiVersioning(options =>
|
||||
{
|
||||
options.AssumeDefaultVersionWhenUnspecified = true;
|
||||
options.DefaultApiVersion = new ApiVersion(1, 0);
|
||||
options.ReportApiVersions = true;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In this method we set db context , read github readme for set db context
|
||||
/// </summary>
|
||||
/// <typeparam name="ContextT">Type of your DataBase Context</typeparam>
|
||||
/// <typeparam name="StartUpAssembly">Type of your asp project startup for check assembly for model builder</typeparam>
|
||||
/// <param name="serviceCollection"></param>
|
||||
/// <param name="optionAction"></param>
|
||||
public static void AddiPackageDbContext<ContextT,StartUpAssembly>(
|
||||
this IServiceCollection serviceCollection,
|
||||
Action<DbContextOptionsBuilder> optionAction)
|
||||
where ContextT : DbContext
|
||||
{
|
||||
Action<DbContextOptionsBuilder> action = options =>
|
||||
{
|
||||
options.UseProjectAssembly(typeof(StartUpAssembly).Assembly);
|
||||
};
|
||||
serviceCollection.AddDbContext<ContextT>(action+optionAction);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,309 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using iPackage.Extensions;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Pluralize.NET;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using Swashbuckle.AspNetCore.SwaggerUI;
|
||||
|
||||
namespace iPackage.Core.Web.WebFramework.Configurations
|
||||
{
|
||||
public static class SwaggerConfiguration
|
||||
{
|
||||
public static void AddCustomSwagger(this IServiceCollection services, string baseUrl)
|
||||
{
|
||||
|
||||
services.AddSwaggerGen(options =>
|
||||
{
|
||||
//var xmlDuc = Path.Combine(AppContext.BaseDirectory, "swaggerApi.xml");
|
||||
//options.IncludeXmlComments(xmlDuc,true);
|
||||
options.SwaggerDoc("v1",
|
||||
new OpenApiInfo
|
||||
{
|
||||
Version = "v1",
|
||||
Title = "iGarson Api Dacument",
|
||||
Description = "iGarson api for clients that wana use",
|
||||
License = new OpenApiLicense { Name = "Vira Safir Fanavar " },
|
||||
Contact = new OpenApiContact
|
||||
{
|
||||
Name = "Amir Hossein Khademi",
|
||||
Email = "avvampier@gmail.com",
|
||||
Url = new Uri("http://amir-khademi.ir/")
|
||||
}
|
||||
});
|
||||
options.SwaggerDoc("v2",
|
||||
new OpenApiInfo
|
||||
{
|
||||
Version = "v2",
|
||||
Title = "iGarson Api Dacument",
|
||||
Description = "iGarson api for clients that wana use",
|
||||
License = new OpenApiLicense { Name = "Vira Safir Fanavar " },
|
||||
Contact = new OpenApiContact
|
||||
{
|
||||
Name = "Amir Hossein Khademi",
|
||||
Email = "avvampier@gmail.com",
|
||||
Url = new Uri("http://amir-khademi.ir/")
|
||||
}
|
||||
});
|
||||
//options.EnableAnnotations();
|
||||
options.DescribeAllParametersInCamelCase();
|
||||
options.IgnoreObsoleteActions();
|
||||
|
||||
#region Versioning
|
||||
// Remove version parameter from all Operations
|
||||
options.OperationFilter<RemoveVersionParameters>();
|
||||
|
||||
//set version "api/v{version}/[controller]" from current swagger doc verion
|
||||
options.DocumentFilter<SetVersionInPaths>();
|
||||
|
||||
//Seperate and categorize end-points by doc version
|
||||
options.DocInclusionPredicate((version, desc) =>
|
||||
{
|
||||
|
||||
if (!desc.TryGetMethodInfo(out MethodInfo methodInfo)) return false;
|
||||
var versions = methodInfo.DeclaringType
|
||||
.GetCustomAttributes(true)
|
||||
.OfType<ApiVersionAttribute>()
|
||||
.SelectMany(attr => attr.Versions)
|
||||
.ToList();
|
||||
|
||||
return versions.Any(v => $"v{v.ToString()}" == version);
|
||||
});
|
||||
#endregion
|
||||
|
||||
#region Security
|
||||
|
||||
string url = $"{baseUrl}/api/v1/user/LoginSwagger";
|
||||
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
Type = SecuritySchemeType.OAuth2,
|
||||
Scheme = "Bearer",
|
||||
Name = "Bearer",
|
||||
Flows = new OpenApiOAuthFlows
|
||||
{
|
||||
Password = new OpenApiOAuthFlow
|
||||
{
|
||||
TokenUrl = new Uri(url),
|
||||
}
|
||||
}
|
||||
});
|
||||
options.OperationFilter<UnauthorizedResponsesOperationFilter>(true, "Bearer");
|
||||
|
||||
#endregion
|
||||
|
||||
#region Customize
|
||||
|
||||
options.OperationFilter<ApplySummariesOperationFilter>();
|
||||
|
||||
#endregion
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public static void UseCustomSwaager(this IApplicationBuilder app, string baseUrl)
|
||||
{
|
||||
|
||||
app.UseSwagger();
|
||||
|
||||
app.UseSwaggerUI(options =>
|
||||
{
|
||||
options.DocExpansion(DocExpansion.None);
|
||||
// Display
|
||||
options.DefaultModelExpandDepth(2);
|
||||
options.DefaultModelRendering(ModelRendering.Model);
|
||||
options.DefaultModelsExpandDepth(-1);
|
||||
options.DisplayOperationId();
|
||||
options.DisplayRequestDuration();
|
||||
options.EnableDeepLinking();
|
||||
options.EnableFilter();
|
||||
options.ShowExtensions();
|
||||
|
||||
options.OAuthUseBasicAuthenticationWithAccessCodeGrant();
|
||||
options.SwaggerEndpoint($"{baseUrl}/swagger/v1/swagger.json", "V1 Docs");
|
||||
options.SwaggerEndpoint($"{baseUrl}/swagger/v2/swagger.json", "V2 Docs");
|
||||
});
|
||||
}
|
||||
}
|
||||
public class RemoveVersionParameters : IOperationFilter
|
||||
{
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||
{
|
||||
// Remove version parameter from all Operations
|
||||
var versionParameter = operation.Parameters.SingleOrDefault(p => p.Name == "version");
|
||||
if (versionParameter != null)
|
||||
operation.Parameters.Remove(versionParameter);
|
||||
}
|
||||
}
|
||||
public class SetVersionInPaths : IDocumentFilter
|
||||
{
|
||||
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
|
||||
{
|
||||
if (swaggerDoc == null)
|
||||
throw new ArgumentNullException(nameof(swaggerDoc));
|
||||
|
||||
var replacements = new OpenApiPaths();
|
||||
|
||||
foreach (var (key, value) in swaggerDoc.Paths)
|
||||
{
|
||||
replacements.Add(key.Replace("v{version}", swaggerDoc.Info.Version, StringComparison.InvariantCulture), value);
|
||||
}
|
||||
|
||||
swaggerDoc.Paths = replacements;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class UnauthorizedResponsesOperationFilter : IOperationFilter
|
||||
{
|
||||
private readonly bool includeUnauthorizedAndForbiddenResponses;
|
||||
private readonly string schemeName;
|
||||
|
||||
public UnauthorizedResponsesOperationFilter(bool includeUnauthorizedAndForbiddenResponses, string schemeName = "Bearer")
|
||||
{
|
||||
this.includeUnauthorizedAndForbiddenResponses = includeUnauthorizedAndForbiddenResponses;
|
||||
this.schemeName = schemeName;
|
||||
}
|
||||
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||
{
|
||||
var filters = context.ApiDescription.ActionDescriptor.FilterDescriptors;
|
||||
|
||||
var hasAnynomousEndPoint = context.ApiDescription.ActionDescriptor.EndpointMetadata.Any(e =>
|
||||
e.GetType() == typeof(Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute));
|
||||
|
||||
//var hasAnonymous = filters.Any(p => p.Filter is AllowAnonymousFilter);
|
||||
if (hasAnynomousEndPoint)
|
||||
return;
|
||||
|
||||
/*var hasAuthorize = filters.Any(p => p.Filter is AuthorizeFilter);
|
||||
if (!hasAuthorize)
|
||||
return;*/
|
||||
|
||||
if (includeUnauthorizedAndForbiddenResponses)
|
||||
{
|
||||
operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" });
|
||||
operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" });
|
||||
}
|
||||
|
||||
operation.Security.Add(new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
}
|
||||
},
|
||||
new string[] {}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class ApplySummariesOperationFilter : IOperationFilter
|
||||
{
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||
{
|
||||
var controllerActionDescriptor = context.ApiDescription.ActionDescriptor as ControllerActionDescriptor;
|
||||
if (controllerActionDescriptor == null) return;
|
||||
|
||||
var pluralizer = new Pluralizer();
|
||||
|
||||
var actionName = controllerActionDescriptor.ActionName;
|
||||
var singularizeName = pluralizer.Singularize(controllerActionDescriptor.ControllerName);
|
||||
var pluralizeName = pluralizer.Pluralize(singularizeName);
|
||||
|
||||
var parameterCount = operation.Parameters.Where(p => p.Name != "version" && p.Name != "api-version").Count();
|
||||
|
||||
if (IsGetAllAction())
|
||||
{
|
||||
if (!operation.Summary.HasValue())
|
||||
operation.Summary = $"Returns all {pluralizeName}";
|
||||
}
|
||||
else if (IsActionName("Post", "Create"))
|
||||
{
|
||||
if (!operation.Summary.HasValue())
|
||||
operation.Summary = $"Creates a {singularizeName}";
|
||||
|
||||
if (operation.Parameters.Count > 0 && !operation.Parameters[0].Description.HasValue())
|
||||
operation.Parameters[0].Description = $"A {singularizeName} representation";
|
||||
}
|
||||
else if (IsActionName("Read", "Get"))
|
||||
{
|
||||
if (!operation.Summary.HasValue())
|
||||
operation.Summary = $"Retrieves a {singularizeName} by unique id";
|
||||
|
||||
if (operation.Parameters.Count > 0 && !operation.Parameters[0].Description.HasValue())
|
||||
operation.Parameters[0].Description = $"a unique id for the {singularizeName}";
|
||||
}
|
||||
else if (IsActionName("Put", "Edit", "Update"))
|
||||
{
|
||||
if (!operation.Summary.HasValue())
|
||||
operation.Summary = $"Updates a {singularizeName} by unique id";
|
||||
|
||||
//if (!operation.Parameters[0].Description.HasValue())
|
||||
// operation.Parameters[0].Description = $"A unique id for the {singularizeName}";
|
||||
|
||||
if (operation.Parameters.Count > 0 && !operation.Parameters[0].Description.HasValue())
|
||||
operation.Parameters[0].Description = $"A {singularizeName} representation";
|
||||
}
|
||||
else if (IsActionName("Delete", "Remove"))
|
||||
{
|
||||
if (!operation.Summary.HasValue())
|
||||
operation.Summary = $"Deletes a {singularizeName} by unique id";
|
||||
|
||||
if (operation.Parameters.Count > 0 && !operation.Parameters[0].Description.HasValue())
|
||||
operation.Parameters[0].Description = $"A unique id for the {singularizeName}";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!operation.Summary.HasValue())
|
||||
operation.Summary = $"{actionName} {pluralizeName}";
|
||||
}
|
||||
|
||||
#region Local Functions
|
||||
bool IsGetAllAction()
|
||||
{
|
||||
foreach (var name in new[] { "Get", "Read", "Select" })
|
||||
{
|
||||
if ((actionName.Equals(name, StringComparison.OrdinalIgnoreCase) && parameterCount == 0) ||
|
||||
actionName.Equals($"{name}All", StringComparison.OrdinalIgnoreCase) ||
|
||||
actionName.Equals($"{name}{pluralizeName}", StringComparison.OrdinalIgnoreCase) ||
|
||||
actionName.Equals($"{name}All{singularizeName}", StringComparison.OrdinalIgnoreCase) ||
|
||||
actionName.Equals($"{name}All{pluralizeName}", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsActionName(params string[] names)
|
||||
{
|
||||
foreach (var name in names)
|
||||
{
|
||||
if (actionName.Contains(name, StringComparison.OrdinalIgnoreCase) ||
|
||||
actionName.Contains($"{name}ById", StringComparison.OrdinalIgnoreCase) ||
|
||||
actionName.Contains($"{name}{singularizeName}", StringComparison.OrdinalIgnoreCase) ||
|
||||
actionName.Contains($"{name}{singularizeName}ById", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using iPackage.Models.Api;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace iPackage.Core.Web.WebFramework.Middlewares
|
||||
{
|
||||
public static class ExceptionHandlerMiddlewareExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseExceptionHandlerMiddleware(this IApplicationBuilder applicationBuilder)
|
||||
{
|
||||
return applicationBuilder.UseMiddleware<ExceptionHandlerMiddleware>();
|
||||
}
|
||||
}
|
||||
public class ExceptionHandlerMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly IHostingEnvironment _env;
|
||||
private readonly ILogger<ExceptionHandlerMiddleware> _logger;
|
||||
|
||||
public ExceptionHandlerMiddleware(RequestDelegate next,
|
||||
IHostingEnvironment env,
|
||||
ILogger<ExceptionHandlerMiddleware> logger)
|
||||
{
|
||||
_next = next;
|
||||
_env = env;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
string message = null;
|
||||
HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError;
|
||||
ApiResultStatusCode apiStatusCode = ApiResultStatusCode.ServerError;
|
||||
|
||||
try
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
catch (AppException exception)
|
||||
{
|
||||
_logger.LogError(exception, exception.Message);
|
||||
httpStatusCode = exception.HttpStatusCode;
|
||||
apiStatusCode = exception.ApiStatusCode;
|
||||
|
||||
if (_env.IsDevelopment())
|
||||
{
|
||||
var dic = new Dictionary<string, string>
|
||||
{
|
||||
["Exception"] = exception.Message,
|
||||
["StackTrace"] = exception.StackTrace,
|
||||
};
|
||||
if (exception.InnerException != null)
|
||||
{
|
||||
dic.Add("InnerException.Exception", exception.InnerException.Message);
|
||||
dic.Add("InnerException.StackTrace", exception.InnerException.StackTrace);
|
||||
}
|
||||
if (exception.AdditionalData != null)
|
||||
dic.Add("AdditionalData", JsonConvert.SerializeObject(exception.AdditionalData));
|
||||
|
||||
message = JsonConvert.SerializeObject(dic);
|
||||
}
|
||||
else
|
||||
{
|
||||
message = exception.Message;
|
||||
}
|
||||
await WriteToResponseAsync();
|
||||
}
|
||||
catch (SecurityTokenExpiredException exception)
|
||||
{
|
||||
_logger.LogError(exception, exception.Message);
|
||||
SetUnAuthorizeResponse(exception);
|
||||
await WriteToResponseAsync();
|
||||
}
|
||||
catch (UnauthorizedAccessException exception)
|
||||
{
|
||||
_logger.LogError(exception, exception.Message);
|
||||
SetUnAuthorizeResponse(exception);
|
||||
await WriteToResponseAsync();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.LogError(exception, exception.Message);
|
||||
|
||||
if (_env.IsDevelopment())
|
||||
{
|
||||
var dic = new Dictionary<string, string>
|
||||
{
|
||||
["Exception"] = exception.Message,
|
||||
["InnerException"] = exception.InnerException?.Message,
|
||||
["StackTrace"] = exception.StackTrace,
|
||||
};
|
||||
message = JsonConvert.SerializeObject(dic);
|
||||
}
|
||||
await WriteToResponseAsync();
|
||||
}
|
||||
|
||||
async Task WriteToResponseAsync()
|
||||
{
|
||||
if (context.Response.HasStarted)
|
||||
throw new InvalidOperationException("The response has already started, the http status code middleware will not be executed.");
|
||||
|
||||
var result = new ApiResult(false, apiStatusCode, message);
|
||||
var json = JsonConvert.SerializeObject(result);
|
||||
|
||||
context.Response.StatusCode = (int)httpStatusCode;
|
||||
context.Response.ContentType = "application/json";
|
||||
await context.Response.WriteAsync(json);
|
||||
}
|
||||
|
||||
void SetUnAuthorizeResponse(Exception exception)
|
||||
{
|
||||
httpStatusCode = HttpStatusCode.Unauthorized;
|
||||
apiStatusCode = ApiResultStatusCode.UnAuthorized;
|
||||
|
||||
if (_env.IsDevelopment())
|
||||
{
|
||||
var dic = new Dictionary<string, string>
|
||||
{
|
||||
["Exception"] = exception.Message,
|
||||
["StackTrace"] = exception.StackTrace
|
||||
};
|
||||
if (exception is SecurityTokenExpiredException tokenException)
|
||||
dic.Add("Expires", tokenException.Expires.ToString());
|
||||
|
||||
message = JsonConvert.SerializeObject(dic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<Authors>AmirHossein Khademi</Authors>
|
||||
<Company>ViraSafir</Company>
|
||||
<Version>1.0.2</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\iPackage\iPackage.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
<PackageReference Include="Autofac" Version="5.1.3" />
|
||||
<PackageReference Include="NLog.Targets.Sentry3" Version="4.0.35" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="4.9.3" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.HttpsPolicy" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="4.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.8" />
|
||||
<PackageReference Include="Newtonsoft.Json.Bson" Version="1.0.2" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.8.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.6.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,123 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Autofac;
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
using iPackage.Core.Web.Extensions;
|
||||
using iPackage.Core.Web.Models.Settings;
|
||||
using iPackage.Core.Web.Repositories;
|
||||
using iPackage.Core.Web.Services.Contracts;
|
||||
using iPackage.Core.Web.WebFramework.Configurations;
|
||||
using iPackage.Core.Web.WebFramework.Middlewares;
|
||||
using iPackage.Extensions;
|
||||
using iPackage.Models.Service;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace iPackage.Core.Web
|
||||
{
|
||||
public abstract class iPackageStartup<YourStartUpType>
|
||||
{
|
||||
private SiteSettings _siteSetting;
|
||||
public static string BaseUrl;
|
||||
public iPackageStartup(Microsoft.AspNetCore.Hosting.IHostingEnvironment env)
|
||||
{
|
||||
var builder = new ConfigurationBuilder()
|
||||
.SetBasePath(env.ContentRootPath)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
|
||||
.AddEnvironmentVariables();
|
||||
this.Configuration = builder.Build();
|
||||
_siteSetting = Configuration.GetSection(nameof(SiteSettings)).Get<SiteSettings>();
|
||||
AutoMapperConfig.ConfigurationMapper();
|
||||
BaseUrl = _siteSetting.BaseUrl;
|
||||
}
|
||||
|
||||
public IConfigurationRoot Configuration { get; private set; }
|
||||
|
||||
public ILifetimeScope AutofacContainer { get; private set; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public virtual void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
//services.AddAutoFacServerContainer();
|
||||
services.Configure<SiteSettings>(Configuration.GetSection(nameof(SiteSettings)));
|
||||
services.AddCustomSwagger(BaseUrl);
|
||||
services.AddCustomApiVersioning();
|
||||
services.AddJwtCustomAuthentication(_siteSetting.JwtSettings);
|
||||
services.AddSignalR();
|
||||
services.AddMemoryCache();
|
||||
services.AddControllers(options => { options.Filters.Add(new AuthorizeFilter()); })
|
||||
.AddControllersAsServices()
|
||||
.AddNewtonsoftJson(options =>
|
||||
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
|
||||
);
|
||||
|
||||
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
|
||||
{
|
||||
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
|
||||
};
|
||||
|
||||
services.AddCors(options => options.AddPolicy("CorsPolicy",
|
||||
builder =>
|
||||
{
|
||||
builder.AllowAnyMethod()
|
||||
.AllowAnyHeader()
|
||||
.SetIsOriginAllowed(_ => true)
|
||||
.AllowCredentials();
|
||||
|
||||
}));
|
||||
}
|
||||
|
||||
public virtual void ConfigureContainer(ContainerBuilder builder)
|
||||
{
|
||||
var assembly = typeof(YourStartUpType).Assembly;
|
||||
builder.RegisterAssemblyTypes(assembly)
|
||||
.AssignableTo<IScopedDependency>()
|
||||
.AsImplementedInterfaces()
|
||||
.InstancePerLifetimeScope();
|
||||
builder.RegisterAssemblyTypes(typeof(IRepositoryWrapper).Assembly)
|
||||
.AssignableTo<IScopedDependency>()
|
||||
.AsImplementedInterfaces()
|
||||
.InstancePerLifetimeScope();
|
||||
builder.RegisterAssemblyTypes(typeof(IDbService).Assembly)
|
||||
.AssignableTo<IScopedDependency>()
|
||||
.AsImplementedInterfaces()
|
||||
.InstancePerLifetimeScope();
|
||||
}
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public virtual async void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
|
||||
this.AutofacContainer = app.ApplicationServices.GetAutofacRoot();
|
||||
|
||||
app.UseExceptionHandlerMiddleware();
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
//app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
app.UseAuthentication();
|
||||
|
||||
app.UseCustomSwaager(BaseUrl);
|
||||
|
||||
app.UseDbInitializer();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
|
||||
app.UseCors("CorsPolicy");
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace iPackage.Extensions
|
||||
{
|
||||
|
||||
public static class Assert
|
||||
{
|
||||
public static void NotNull<T>(T obj, string name, string message = null)
|
||||
where T : class
|
||||
{
|
||||
if (obj is null)
|
||||
throw new ArgumentNullException($"{name} : {typeof(T)}", message);
|
||||
}
|
||||
|
||||
public static void NotNull<T>(T? obj, string name, string message = null)
|
||||
where T : struct
|
||||
{
|
||||
if (!obj.HasValue)
|
||||
throw new ArgumentNullException($"{name} : {typeof(T)}", message);
|
||||
|
||||
}
|
||||
|
||||
public static void NotEmpty<T>(T obj, string name, string message = null, T defaultValue = null)
|
||||
where T : class
|
||||
{
|
||||
if (obj == defaultValue
|
||||
|| (obj is string str && string.IsNullOrWhiteSpace(str))
|
||||
|| (obj is IEnumerable list && !list.Cast<object>().Any()))
|
||||
{
|
||||
throw new ArgumentException("Argument is empty : " + message, $"{name} : {typeof(T)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using AutoMapper;
|
||||
using iPackage.Models.Dto;
|
||||
|
||||
namespace iPackage.Extensions
|
||||
{
|
||||
public static class AutoMapperConfig
|
||||
{
|
||||
public static void ConfigurationMapper()
|
||||
{
|
||||
Mapper.Initialize(config => { config.AddCustomMapping(Assembly.GetEntryAssembly()); });
|
||||
Mapper.Configuration.CompileMappings();
|
||||
}
|
||||
|
||||
public static void AddCustomMapping(this IMapperConfigurationExpression expression, Assembly assemblies)
|
||||
{
|
||||
var allTypes = assemblies.ExportedTypes;
|
||||
var list = allTypes
|
||||
.Where(type => type.IsClass && !type.IsAbstract && type.GetInterfaces().Contains(typeof(IMapperConf)))
|
||||
.Select(type => (IMapperConf)Activator.CreateInstance(type)).ToList();
|
||||
expression.AddProfile(new CustomMappingProfile(list));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace iPackage.Extensions
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
public static IEnumerable<T> GetEnumValues<T>(this T input) where T : struct
|
||||
{
|
||||
if (!typeof(T).IsEnum)
|
||||
throw new NotSupportedException();
|
||||
|
||||
return Enum.GetValues(input.GetType()).Cast<T>();
|
||||
}
|
||||
|
||||
public static IEnumerable<T> GetEnumFlags<T>(this T input) where T : struct
|
||||
{
|
||||
if (!typeof(T).IsEnum)
|
||||
throw new NotSupportedException();
|
||||
|
||||
foreach (var value in Enum.GetValues(input.GetType()))
|
||||
if ((input as Enum).HasFlag(value as Enum))
|
||||
yield return (T)value;
|
||||
}
|
||||
|
||||
public static string ToDisplay(this Enum value, DisplayProperty property = DisplayProperty.Name)
|
||||
{
|
||||
Assert.NotNull(value, nameof(value));
|
||||
|
||||
var attribute = value.GetType().GetField(value.ToString())
|
||||
.GetCustomAttributes<DisplayAttribute>(false).FirstOrDefault();
|
||||
|
||||
if (attribute == null)
|
||||
return value.ToString();
|
||||
|
||||
var propValue = attribute.GetType().GetProperty(property.ToString()).GetValue(attribute, null);
|
||||
return propValue.ToString();
|
||||
}
|
||||
|
||||
public static Dictionary<int, string> ToDictionary(this Enum value)
|
||||
{
|
||||
return Enum.GetValues(value.GetType()).Cast<Enum>().ToDictionary(p => Convert.ToInt32(p), q => ToDisplay(q));
|
||||
}
|
||||
}
|
||||
|
||||
public enum DisplayProperty
|
||||
{
|
||||
Description,
|
||||
GroupName,
|
||||
Name,
|
||||
Prompt,
|
||||
ShortName,
|
||||
Order
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace iPackage.Extensions
|
||||
{
|
||||
public static class PropertyExtensions
|
||||
{
|
||||
|
||||
public static string GetPropertyDisplayName(this MemberInfo propertyExpression)
|
||||
{
|
||||
var memberInfo = propertyExpression;
|
||||
var attr = memberInfo.GetCustomAttributes<DisplayAttribute>().FirstOrDefault();
|
||||
if (attr == null)
|
||||
{
|
||||
return memberInfo.Name;
|
||||
}
|
||||
|
||||
return attr.Name;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace iPackage.Extensions
|
||||
{
|
||||
public static class SecurityHelper
|
||||
{
|
||||
public static string GetSha256Hash(string input)
|
||||
{
|
||||
//using (var sha256 = new SHA256CryptoServiceProvider())
|
||||
using (var sha256 = SHA256.Create())
|
||||
{
|
||||
var byteValue = Encoding.UTF8.GetBytes(input);
|
||||
var byteHash = sha256.ComputeHash(byteValue);
|
||||
return Convert.ToBase64String(byteHash);
|
||||
//return BitConverter.ToString(byteHash).Replace("-", "").ToLower();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace iPackage.Extensions
|
||||
{
|
||||
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static bool HasValue(this string value, bool ignoreWhiteSpace = true)
|
||||
{
|
||||
return ignoreWhiteSpace ? !string.IsNullOrWhiteSpace(value) : !string.IsNullOrEmpty(value);
|
||||
}
|
||||
|
||||
public static int ToInt(this string value)
|
||||
{
|
||||
return Convert.ToInt32(value);
|
||||
}
|
||||
|
||||
public static decimal ToDecimal(this string value)
|
||||
{
|
||||
return Convert.ToDecimal(value);
|
||||
}
|
||||
|
||||
public static string ToNumeric(this int value)
|
||||
{
|
||||
return value.ToString("N0"); //"123,456"
|
||||
}
|
||||
|
||||
public static string ToNumeric(this decimal value)
|
||||
{
|
||||
return value.ToString("N0");
|
||||
}
|
||||
|
||||
public static string ToCurrency(this int value)
|
||||
{
|
||||
//fa-IR => current culture currency symbol => ریال
|
||||
//123456 => "123,123ریال"
|
||||
return value.ToString("C0");
|
||||
}
|
||||
|
||||
public static string ToCurrency(this decimal value)
|
||||
{
|
||||
return value.ToString("C0");
|
||||
}
|
||||
|
||||
public static string En2Fa(this string str)
|
||||
{
|
||||
return str.Replace("0", "۰")
|
||||
.Replace("1", "۱")
|
||||
.Replace("2", "۲")
|
||||
.Replace("3", "۳")
|
||||
.Replace("4", "۴")
|
||||
.Replace("5", "۵")
|
||||
.Replace("6", "۶")
|
||||
.Replace("7", "۷")
|
||||
.Replace("8", "۸")
|
||||
.Replace("9", "۹");
|
||||
}
|
||||
|
||||
public static string Fa2En(this string str)
|
||||
{
|
||||
return str.Replace("۰", "0")
|
||||
.Replace("۱", "1")
|
||||
.Replace("۲", "2")
|
||||
.Replace("۳", "3")
|
||||
.Replace("۴", "4")
|
||||
.Replace("۵", "5")
|
||||
.Replace("۶", "6")
|
||||
.Replace("۷", "7")
|
||||
.Replace("۸", "8")
|
||||
.Replace("۹", "9")
|
||||
//iphone numeric
|
||||
.Replace("٠", "0")
|
||||
.Replace("١", "1")
|
||||
.Replace("٢", "2")
|
||||
.Replace("٣", "3")
|
||||
.Replace("٤", "4")
|
||||
.Replace("٥", "5")
|
||||
.Replace("٦", "6")
|
||||
.Replace("٧", "7")
|
||||
.Replace("٨", "8")
|
||||
.Replace("٩", "9");
|
||||
}
|
||||
|
||||
public static string FixPersianChars(this string str)
|
||||
{
|
||||
return str.Replace("ﮎ", "ک")
|
||||
.Replace("ﮏ", "ک")
|
||||
.Replace("ﮐ", "ک")
|
||||
.Replace("ﮑ", "ک")
|
||||
.Replace("ك", "ک")
|
||||
.Replace("ي", "ی")
|
||||
.Replace(" ", " ")
|
||||
.Replace("", " ")
|
||||
.Replace("ھ", "ه");//.Replace("ئ", "ی");
|
||||
}
|
||||
|
||||
public static string CleanString(this string str)
|
||||
{
|
||||
return str.Trim().FixPersianChars().Fa2En().NullIfEmpty();
|
||||
}
|
||||
|
||||
public static string NullIfEmpty(this string str)
|
||||
{
|
||||
return str?.Length == 0 ? null : str;
|
||||
}
|
||||
public static string GetId(int length = 8)
|
||||
{
|
||||
return Guid.NewGuid().ToString("N").Substring(0, length);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace iPackage.Extensions
|
||||
{
|
||||
public static class ValidationExtensions
|
||||
{
|
||||
public static bool CheckDateIs(this DateTime dateTime, DateTime From, DateTime To)
|
||||
{
|
||||
if (dateTime.Date > To.Date && dateTime.Date < From.Date)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
public static bool CheckDateFromToNow(this DateTime dateTime, int fromDays = 5)
|
||||
{
|
||||
var From = DateTime.Now.AddDays(-fromDays);
|
||||
var To = DateTime.Now;
|
||||
if (dateTime.Date > To.Date && dateTime.Date < From.Date)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Text;
|
||||
|
||||
namespace iPackage.Models.Api
|
||||
{
|
||||
public class AccessToken
|
||||
{
|
||||
public string access_token { get; set; }
|
||||
public string refresh_token { get; set; }
|
||||
public string token_type { get; set; }
|
||||
public int expires_in { get; set; }
|
||||
|
||||
public AccessToken(JwtSecurityToken securityToken)
|
||||
{
|
||||
access_token = new JwtSecurityTokenHandler().WriteToken(securityToken);
|
||||
token_type = "Bearer";
|
||||
expires_in = (int)(securityToken.ValidTo - DateTime.UtcNow).TotalSeconds;
|
||||
}
|
||||
}
|
||||
public class AccessToken<TUser>
|
||||
{
|
||||
public string access_token { get; set; }
|
||||
public string refresh_token { get; set; }
|
||||
public string token_type { get; set; }
|
||||
public int expires_in { get; set; }
|
||||
public TUser User { get; set; }
|
||||
public AccessToken(JwtSecurityToken securityToken)
|
||||
{
|
||||
access_token = new JwtSecurityTokenHandler().WriteToken(securityToken);
|
||||
token_type = "Bearer";
|
||||
expires_in = (int)(securityToken.ValidTo - DateTime.UtcNow).TotalSeconds;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using iPackage.Extensions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace iPackage.Models.Api
|
||||
{
|
||||
public enum ApiResultStatusCode
|
||||
{
|
||||
[Display(Name = "عملیات با موفقیت انجام شد")]
|
||||
Success = 0,
|
||||
|
||||
[Display(Name = "خطایی در سرور رخ داده است")]
|
||||
ServerError = 1,
|
||||
|
||||
[Display(Name = "پارامتر های ارسالی معتبر نیستند")]
|
||||
BadRequest = 2,
|
||||
|
||||
[Display(Name = "یافت نشد")]
|
||||
NotFound = 3,
|
||||
|
||||
[Display(Name = "لیست خالی است")]
|
||||
ListEmpty = 4,
|
||||
|
||||
[Display(Name = "خطایی در پردازش رخ داد")]
|
||||
LogicError = 5,
|
||||
|
||||
[Display(Name = "خطای احراز هویت")]
|
||||
UnAuthorized = 6,
|
||||
|
||||
[Display(Name = "مقدار غذای درخواستی بیشتر است")]
|
||||
FoodLimited = 7
|
||||
}
|
||||
public class ApiResult
|
||||
{
|
||||
public bool IsSuccess { get; set; }
|
||||
public ApiResultStatusCode StatusCode { get; set; }
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Message { get; set; }
|
||||
public ApiResult(bool isSuccess, ApiResultStatusCode statusCode, string message = null)
|
||||
{
|
||||
IsSuccess = isSuccess;
|
||||
StatusCode = statusCode;
|
||||
Message = message ?? statusCode.ToDisplay();
|
||||
}
|
||||
|
||||
#region Implicit Operators
|
||||
public static implicit operator ApiResult(OkResult result)
|
||||
{
|
||||
return new ApiResult(true, ApiResultStatusCode.Success);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult(BadRequestResult result)
|
||||
{
|
||||
return new ApiResult(false, ApiResultStatusCode.BadRequest);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult(BadRequestObjectResult result)
|
||||
{
|
||||
var message = result.Value.ToString();
|
||||
if (result.Value is SerializableError errors)
|
||||
{
|
||||
var errorMessages = errors.SelectMany(p => (string[])p.Value).Distinct();
|
||||
message = string.Join(" | ", errorMessages);
|
||||
}
|
||||
return new ApiResult(false, ApiResultStatusCode.BadRequest, message);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult(ContentResult result)
|
||||
{
|
||||
return new ApiResult(true, ApiResultStatusCode.Success, result.Content);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult(NotFoundResult result)
|
||||
{
|
||||
return new ApiResult(false, ApiResultStatusCode.NotFound);
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
public class ApiResult<TData> : ApiResult
|
||||
where TData : class
|
||||
{
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public TData Data { get; set; }
|
||||
|
||||
public ApiResult(bool isSuccess, ApiResultStatusCode statusCode, TData data, string message = null)
|
||||
: base(isSuccess, statusCode, message)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
||||
#region Implicit Operators
|
||||
public static implicit operator ApiResult<TData>(TData data)
|
||||
{
|
||||
return new ApiResult<TData>(true, ApiResultStatusCode.Success, data);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult<TData>(OkResult result)
|
||||
{
|
||||
return new ApiResult<TData>(true, ApiResultStatusCode.Success, null);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult<TData>(OkObjectResult result)
|
||||
{
|
||||
return new ApiResult<TData>(true, ApiResultStatusCode.Success, (TData)result.Value);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult<TData>(BadRequestResult result)
|
||||
{
|
||||
return new ApiResult<TData>(false, ApiResultStatusCode.BadRequest, null);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult<TData>(BadRequestObjectResult result)
|
||||
{
|
||||
var message = result.Value.ToString();
|
||||
if (result.Value is SerializableError errors)
|
||||
{
|
||||
var errorMessages = errors.SelectMany(p => (string[])p.Value).Distinct();
|
||||
message = string.Join(" | ", errorMessages);
|
||||
}
|
||||
return new ApiResult<TData>(false, ApiResultStatusCode.BadRequest, null, message);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult<TData>(ContentResult result)
|
||||
{
|
||||
return new ApiResult<TData>(true, ApiResultStatusCode.Success, null, result.Content);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult<TData>(NotFoundResult result)
|
||||
{
|
||||
return new ApiResult<TData>(false, ApiResultStatusCode.NotFound, null);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult<TData>(NotFoundObjectResult result)
|
||||
{
|
||||
return new ApiResult<TData>(false, ApiResultStatusCode.NotFound, (TData)result.Value);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace iPackage.Models.Api
|
||||
{
|
||||
|
||||
|
||||
public class AppException : Exception
|
||||
{
|
||||
public HttpStatusCode HttpStatusCode { get; set; }
|
||||
public ApiResultStatusCode ApiStatusCode { get; set; }
|
||||
public object AdditionalData { get; set; }
|
||||
|
||||
public AppException()
|
||||
: this(ApiResultStatusCode.ServerError)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(ApiResultStatusCode statusCode)
|
||||
: this(statusCode, null)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(string message)
|
||||
: this(ApiResultStatusCode.ServerError, message)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(ApiResultStatusCode statusCode, string message)
|
||||
: this(statusCode, message, HttpStatusCode.InternalServerError)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(string message, object additionalData)
|
||||
: this(ApiResultStatusCode.ServerError, message, additionalData)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(ApiResultStatusCode statusCode, object additionalData)
|
||||
: this(statusCode, null, additionalData)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(ApiResultStatusCode statusCode, string message, object additionalData)
|
||||
: this(statusCode, message, HttpStatusCode.InternalServerError, additionalData)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(ApiResultStatusCode statusCode, string message, HttpStatusCode httpStatusCode)
|
||||
: this(statusCode, message, httpStatusCode, null)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(ApiResultStatusCode statusCode, string message, HttpStatusCode httpStatusCode, object additionalData)
|
||||
: this(statusCode, message, httpStatusCode, null, additionalData)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(string message, Exception exception)
|
||||
: this(ApiResultStatusCode.ServerError, message, exception)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(string message, Exception exception, object additionalData)
|
||||
: this(ApiResultStatusCode.ServerError, message, exception, additionalData)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(ApiResultStatusCode statusCode, string message, Exception exception)
|
||||
: this(statusCode, message, HttpStatusCode.InternalServerError, exception)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(ApiResultStatusCode statusCode, string message, Exception exception, object additionalData)
|
||||
: this(statusCode, message, HttpStatusCode.InternalServerError, exception, additionalData)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(ApiResultStatusCode statusCode, string message, HttpStatusCode httpStatusCode, Exception exception)
|
||||
: this(statusCode, message, httpStatusCode, exception, null)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(ApiResultStatusCode statusCode, string message, HttpStatusCode httpStatusCode, Exception exception, object additionalData)
|
||||
: base(message, exception)
|
||||
{
|
||||
ApiStatusCode = statusCode;
|
||||
HttpStatusCode = httpStatusCode;
|
||||
AdditionalData = additionalData;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue