├── .editorconfig ├── .gitattributes ├── .gitignore ├── Directory.Build.props ├── LICENSE ├── README.md ├── Samples.sln ├── appveyor.yml └── src ├── AspNetIdentityAndEFCore ├── Areas │ └── Identity │ │ └── Pages │ │ └── _ViewStart.cshtml ├── AspNetIdentityAndEFCore.csproj ├── Controllers │ └── HomeController.cs ├── Data │ ├── ApplicationDbContext.cs │ └── Migrations │ │ ├── 20191029065610_AspIdentityWithMultiTenancy.Designer.cs │ │ ├── 20191029065610_AspIdentityWithMultiTenancy.cs │ │ └── ApplicationDbContextModelSnapshot.cs ├── Models │ ├── ApplicationTenant.cs │ ├── ApplicationUser.cs │ └── ErrorViewModel.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── SeedData.cs ├── Startup.cs ├── Views │ ├── Home │ │ ├── Index.cshtml │ │ └── Privacy.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ ├── _Layout.cshtml │ │ ├── _LoginPartial.cshtml │ │ └── _ValidationScriptsPartial.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml ├── appsettings.Development.json ├── appsettings.json └── wwwroot │ ├── css │ └── site.css │ ├── favicon.ico │ ├── js │ └── site.js │ └── lib │ ├── bootstrap │ ├── LICENSE │ └── dist │ │ ├── css │ │ ├── bootstrap-grid.css │ │ ├── bootstrap-grid.css.map │ │ ├── bootstrap-grid.min.css │ │ ├── bootstrap-grid.min.css.map │ │ ├── bootstrap-reboot.css │ │ ├── bootstrap-reboot.css.map │ │ ├── bootstrap-reboot.min.css │ │ ├── bootstrap-reboot.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ │ └── js │ │ ├── bootstrap.bundle.js │ │ ├── bootstrap.bundle.js.map │ │ ├── bootstrap.bundle.min.js │ │ ├── bootstrap.bundle.min.js.map │ │ ├── bootstrap.js │ │ ├── bootstrap.js.map │ │ ├── bootstrap.min.js │ │ └── bootstrap.min.js.map │ ├── jquery-validation-unobtrusive │ ├── LICENSE.txt │ ├── jquery.validate.unobtrusive.js │ └── jquery.validate.unobtrusive.min.js │ ├── jquery-validation │ ├── LICENSE.md │ └── dist │ │ ├── additional-methods.js │ │ ├── additional-methods.min.js │ │ ├── jquery.validate.js │ │ └── jquery.validate.min.js │ └── jquery │ ├── LICENSE.txt │ └── dist │ ├── jquery.js │ ├── jquery.min.js │ └── jquery.min.map └── Int64AspNetIdentityAndEFCore ├── Areas └── Identity │ └── Pages │ └── _ViewStart.cshtml ├── Controllers └── HomeController.cs ├── Data ├── ApplicationDbContext.cs └── Migrations │ ├── 20191029065621_AspIdentityWithMultiTenancy.Designer.cs │ ├── 20191029065621_AspIdentityWithMultiTenancy.cs │ └── ApplicationDbContextModelSnapshot.cs ├── Int64AspNetIdentityAndEFCore.csproj ├── Models ├── ApplicationTenant.cs ├── ApplicationUser.cs └── ErrorViewModel.cs ├── Program.cs ├── Properties └── launchSettings.json ├── SeedData.cs ├── Startup.cs ├── Views ├── Home │ ├── Index.cshtml │ └── Privacy.cshtml ├── Shared │ ├── Error.cshtml │ ├── _Layout.cshtml │ ├── _LoginPartial.cshtml │ └── _ValidationScriptsPartial.cshtml ├── _ViewImports.cshtml └── _ViewStart.cshtml ├── appsettings.Development.json ├── appsettings.json └── wwwroot ├── css └── site.css ├── favicon.ico ├── js └── site.js └── lib ├── bootstrap ├── LICENSE └── dist │ ├── css │ ├── bootstrap-grid.css │ ├── bootstrap-grid.css.map │ ├── bootstrap-grid.min.css │ ├── bootstrap-grid.min.css.map │ ├── bootstrap-reboot.css │ ├── bootstrap-reboot.css.map │ ├── bootstrap-reboot.min.css │ ├── bootstrap-reboot.min.css.map │ ├── bootstrap.css │ ├── bootstrap.css.map │ ├── bootstrap.min.css │ └── bootstrap.min.css.map │ └── js │ ├── bootstrap.bundle.js │ ├── bootstrap.bundle.js.map │ ├── bootstrap.bundle.min.js │ ├── bootstrap.bundle.min.js.map │ ├── bootstrap.js │ ├── bootstrap.js.map │ ├── bootstrap.min.js │ └── bootstrap.min.js.map ├── jquery-validation-unobtrusive ├── LICENSE.txt ├── jquery.validate.unobtrusive.js └── jquery.validate.unobtrusive.min.js ├── jquery-validation ├── LICENSE.md └── dist │ ├── additional-methods.js │ ├── additional-methods.min.js │ ├── jquery.validate.js │ └── jquery.validate.min.js └── jquery ├── LICENSE.txt └── dist ├── jquery.js ├── jquery.min.js └── jquery.min.map /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference?view=vs-2019 2 | root = true 3 | 4 | # All files 5 | [*] 6 | indent_style = space 7 | 8 | # Code files 9 | [*.{cs,csx,vb,vbx,js,json,xml,config,yaml,props}] 10 | indent_size = 4 11 | end_of_line = lf 12 | insert_final_newline = true 13 | trim_trailing_whitespace = true 14 | charset = utf-8-bom 15 | 16 | ############################### 17 | # .NET Coding Conventions # 18 | ############################### 19 | 20 | [*.{cs,vb}] 21 | # Organize usings 22 | dotnet_sort_system_directives_first = true 23 | dotnet_separate_import_directive_groups = false 24 | 25 | # this. preferences 26 | dotnet_style_qualification_for_field = false:warning 27 | dotnet_style_qualification_for_property = false:warning 28 | dotnet_style_qualification_for_method = false:warning 29 | dotnet_style_qualification_for_event = false:warning 30 | 31 | # Language keywords vs BCL types preferences 32 | dotnet_style_predefined_type_for_locals_parameters_members = true:warning 33 | dotnet_style_predefined_type_for_member_access = true:warning 34 | 35 | # Parentheses preferences 36 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning 37 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning 38 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning 39 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:none 40 | 41 | # Modifier preferences 42 | dotnet_style_require_accessibility_modifiers = always:error 43 | dotnet_style_readonly_field = true:error 44 | 45 | # Expression-level preferences 46 | dotnet_style_object_initializer = true:warning 47 | dotnet_style_collection_initializer = true:warning 48 | dotnet_style_explicit_tuple_names = true:warning 49 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 50 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 51 | dotnet_style_prefer_auto_properties = true:warning 52 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 53 | dotnet_style_prefer_conditional_expression_over_assignment = true:none 54 | dotnet_style_prefer_conditional_expression_over_return = true:none 55 | 56 | # Null-checking preferences 57 | dotnet_style_coalesce_expression = true:error 58 | dotnet_style_null_propagation = true:error 59 | 60 | ############################### 61 | # C# Code Style Rules # 62 | ############################### 63 | 64 | [*.cs] 65 | # var preferences 66 | csharp_style_var_for_built_in_types = true:error 67 | csharp_style_var_when_type_is_apparent = true:error 68 | csharp_style_var_elsewhere = true:error 69 | 70 | # Expression-bodied members 71 | csharp_style_expression_bodied_methods = false:none 72 | csharp_style_expression_bodied_constructors = false:none 73 | csharp_style_expression_bodied_operators = false:none 74 | csharp_style_expression_bodied_properties = true:none 75 | csharp_style_expression_bodied_indexers = true:none 76 | csharp_style_expression_bodied_accessors = true:none 77 | 78 | # Pattern-matching preferences 79 | csharp_style_pattern_matching_over_is_with_cast_check = true:warning 80 | csharp_style_pattern_matching_over_as_with_null_check = true:warning 81 | 82 | # Null-checking preferences 83 | csharp_style_throw_expression = true:suggestion 84 | csharp_style_conditional_delegate_call = true:suggestion 85 | 86 | # Modifier preferences 87 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:error 88 | 89 | # Expression-level preferences 90 | csharp_prefer_simple_default_expression = true:error 91 | csharp_style_deconstructed_variable_declaration = true:suggestion 92 | csharp_style_pattern_local_over_anonymous_function = true:warning 93 | 94 | # Code block preferences 95 | csharp_prefer_braces = true:error 96 | 97 | # Inlined variable declarations 98 | csharp_style_inlined_variable_declaration = true:error 99 | 100 | ############################### 101 | # C# Formatting Rules # 102 | ############################### 103 | 104 | # New line preferences 105 | csharp_new_line_before_open_brace = all 106 | csharp_new_line_before_else = true 107 | csharp_new_line_before_catch = true 108 | csharp_new_line_before_finally = true 109 | csharp_new_line_before_members_in_object_initializers = true 110 | csharp_new_line_before_members_in_anonymous_types = true 111 | csharp_new_line_between_query_expression_clauses = true 112 | 113 | # Indentation preferences 114 | csharp_indent_case_contents = true 115 | csharp_indent_switch_labels = true 116 | csharp_indent_labels = flush_left 117 | 118 | # Space preferences 119 | csharp_space_after_cast = false 120 | csharp_space_after_keywords_in_control_flow_statements = true 121 | csharp_space_between_method_call_parameter_list_parentheses = false 122 | csharp_space_between_method_declaration_parameter_list_parentheses = false 123 | csharp_space_between_parentheses = false 124 | csharp_space_before_colon_in_inheritance_clause = true 125 | csharp_space_after_colon_in_inheritance_clause = true 126 | csharp_space_around_binary_operators = before_and_after 127 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 128 | csharp_space_between_method_call_name_and_opening_parenthesis = false 129 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 130 | csharp_space_after_comma = true 131 | csharp_space_after_dot = false 132 | 133 | # Wrapping preferences 134 | csharp_preserve_single_line_statements = false 135 | csharp_preserve_single_line_blocks = true 136 | 137 | ############################### 138 | # Naming Conventions # 139 | ############################### 140 | 141 | # Style Definitions 142 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case 143 | dotnet_naming_style.camel_case_style.capitalization = camel_case 144 | dotnet_naming_style.camel_case_with_underscore_prefix_style.capitalization = camel_case 145 | dotnet_naming_style.camel_case_with_underscore_prefix_style.required_prefix = _ 146 | dotnet_naming_style.pascal_case_with_i_prefix_style.capitalization = pascal_case 147 | dotnet_naming_style.pascal_case_with_i_prefix_style.required_prefix = I 148 | dotnet_naming_style.pascal_case_with_t_prefix_style.capitalization = pascal_case 149 | dotnet_naming_style.pascal_case_with_t_prefix_style.required_prefix = T 150 | dotnet_naming_style.pascal_case_with_async_suffix_style.capitalization = pascal_case 151 | dotnet_naming_style.pascal_case_with_async_suffix_style.required_suffix = Async 152 | 153 | # interfaces should be in pascal case and begin with I 154 | dotnet_naming_rule.interfaces_should_begin_with_i.severity = error 155 | dotnet_naming_rule.interfaces_should_begin_with_i.symbols = interfaces 156 | dotnet_naming_rule.interfaces_should_begin_with_i.style = pascal_case_with_i_prefix_style 157 | dotnet_naming_symbols.interfaces.applicable_kinds = interface 158 | dotnet_naming_symbols.interfaces.applicable_accessibilities = * 159 | 160 | # type parameters should be in pascal case and begin with T 161 | dotnet_naming_rule.type_parameters_should_begin_with_t.severity = error 162 | dotnet_naming_rule.type_parameters_should_begin_with_t.symbols = type_parameters 163 | dotnet_naming_rule.type_parameters_should_begin_with_t.style = pascal_case_with_t_prefix_style 164 | dotnet_naming_symbols.type_parameters.applicable_kinds = type_parameter 165 | 166 | # async methods should be in pascal case and end with Async 167 | dotnet_naming_rule.async_methods_should_end_with_async.severity = error 168 | dotnet_naming_rule.async_methods_should_end_with_async.symbols = async_methods 169 | dotnet_naming_rule.async_methods_should_end_with_async.style = pascal_case_with_async_suffix_style 170 | dotnet_naming_symbols.async_methods.applicable_kinds = method 171 | dotnet_naming_symbols.async_methods.applicable_accessibilities = * 172 | dotnet_naming_symbols.async_methods.required_modifiers = async 173 | 174 | # locals should be in camel case 175 | dotnet_naming_rule.locals_should_be_camel_case.severity = error 176 | dotnet_naming_rule.locals_should_be_camel_case.symbols = parameters 177 | dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style 178 | dotnet_naming_symbols.parameters.applicable_kinds = parameter,local,local_function 179 | 180 | # private fields should be in camel case and begin with an underscore 181 | dotnet_naming_rule.private_fields_should_begin_with_underscore.severity = error 182 | dotnet_naming_rule.private_fields_should_begin_with_underscore.symbols = private_fields 183 | dotnet_naming_rule.private_fields_should_begin_with_underscore.style = camel_case_with_underscore_prefix_style 184 | dotnet_naming_symbols.private_fields.applicable_kinds = field 185 | dotnet_naming_symbols.private_fields.applicable_accessibilities = private 186 | 187 | # all remaining symbols should be in pascal case 188 | dotnet_naming_rule.symbols_should_be_pascal_case.severity = error 189 | dotnet_naming_rule.symbols_should_be_pascal_case.symbols = all_symbols 190 | dotnet_naming_rule.symbols_should_be_pascal_case.style = pascal_case_style 191 | dotnet_naming_symbols.all_symbols.applicable_kinds = * 192 | dotnet_naming_symbols.all_symbols.applicable_accessibilities = * -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | [Ss]tyle[Cc]op.* 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # LightSwitch generated files 235 | GeneratedArtifacts/ 236 | ModelManifest.xml 237 | 238 | # Paket dependency manager 239 | .paket/paket.exe 240 | 241 | # FAKE - F# Make 242 | .fake/ 243 | 244 | # Local NUGET Feed 245 | nuget-pack-to-local-feed.ps1 -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Kris Penner 5 | 6 | MultiTenancyServer 7 | Copyright © Kris Penner. All rights reserved. 8 | en-US 9 | true 10 | https://raw.githubusercontent.com/MultiTenancyServer/MultiTenancyServer.Samples/master/LICENSE 11 | https://github.com/MultiTenancyServer 12 | https://avatars3.githubusercontent.com/u/38764835 13 | https://github.com/MultiTenancyServer/MultiTenancyServer.Samples 14 | git 15 | true 16 | true 17 | embedded 18 | false 19 | true 20 | $(MSBuildProjectName.Contains('Test')) 21 | true 22 | true 23 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb 24 | latest 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Moved to https://github.com/MultiTenancyServer/MultiTenancyServer/tree/master/samples 2 | 3 | 4 | # MultiTenancyServer.Samples 5 | 6 | See [MultiTenancyServer README](https://github.com/MultiTenancyServer/MultiTenancyServer). 7 | 8 | All examples will register two tenants (tenant1 and tenant2) along with three users with one user, alice, registered within both tenants. You should launch a sample project as an exe when debugging instead of via IIS Express so the /seed command line argument is passed in which will generate the Sqlite database(s) in the project folder and populate with the above mentioned tenants and users. All user passwords are Pass123$. 9 | 10 | |User|Tenant|Password| 11 | |---|---|---| 12 | |alice@contoso.com|tenant1 & tenant2|Pass123$| 13 | |bob@contoso.com|tenant1|Pass123$| 14 | |chris@contoso.com|tenant2|Pass123$| 15 | 16 | ## ASP.NET Core Identity 17 | Sample project: [AspNetIdentityAndEFCore](https://github.com/MultiTenancyServer/MultiTenancyServer.Samples/tree/master/src/AspNetIdentityAndEFCore)
18 | Components: ASP.NET Core Identity and Entity Framework Core
19 | Database model: single database with tenancy shadow columns
20 | 21 | ## ASP.NET Core Identity using Int64 22 | Sample project: [Int64AspNetIdentityAndEFCore](https://github.com/MultiTenancyServer/MultiTenancyServer.Samples/tree/master/src/Int64AspNetIdentityAndEFCore)
23 | Components: ASP.NET Core Identity and Entity Framework Core
24 | Database model: single database with tenancy shadow columns
25 | 26 | ## Identity Server 4 27 | Sample project: [IdentityServerWithAspIdAndEF](https://github.com/MultiTenancyServer/MultiTenancyServer.Samples/tree/master/src/IdentityServerWithAspIdAndEF)
28 | Components: Identity Server 4, ASP.NET Core Identity and Entity Framework Core
29 | Database model: single database with tenancy shadow columns
30 | 31 | ## Database per tenant 32 | Sample project: [DatabasePerTenantAspIdAndEF](https://github.com/MultiTenancyServer/MultiTenancyServer.Samples/tree/master/src/DatabasePerTenantAspIdAndEF)
33 | Components: ASP.NET Core Identity and Entity Framework Core
34 | Database model: database per tenant
35 | -------------------------------------------------------------------------------- /Samples.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29409.12 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4598A16C-EB72-4B22-A425-800AEB9263F8}" 7 | ProjectSection(SolutionItems) = preProject 8 | .editorconfig = .editorconfig 9 | .gitignore = .gitignore 10 | appveyor.yml = appveyor.yml 11 | Directory.Build.props = Directory.Build.props 12 | LICENSE = LICENSE 13 | README.md = README.md 14 | EndProjectSection 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetIdentityAndEFCore", "src\AspNetIdentityAndEFCore\AspNetIdentityAndEFCore.csproj", "{C153D7A8-C69C-4C7D-BED4-08379E08A8F6}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Int64AspNetIdentityAndEFCore", "src\Int64AspNetIdentityAndEFCore\Int64AspNetIdentityAndEFCore.csproj", "{440CAE78-91DA-46A0-89F5-779B5919ED62}" 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Release|Any CPU = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {C153D7A8-C69C-4C7D-BED4-08379E08A8F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {C153D7A8-C69C-4C7D-BED4-08379E08A8F6}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {C153D7A8-C69C-4C7D-BED4-08379E08A8F6}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {C153D7A8-C69C-4C7D-BED4-08379E08A8F6}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {440CAE78-91DA-46A0-89F5-779B5919ED62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {440CAE78-91DA-46A0-89F5-779B5919ED62}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {440CAE78-91DA-46A0-89F5-779B5919ED62}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {440CAE78-91DA-46A0-89F5-779B5919ED62}.Release|Any CPU.Build.0 = Release|Any CPU 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {6B0D0450-4DDB-424C-80A0-FA566EABFE74} 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2019 2 | version: '{build}' 3 | configuration: Release 4 | skip_tags: true 5 | pull_requests: 6 | do_not_increment_build_number: true 7 | nuget: 8 | account_feed: false 9 | project_feed: false 10 | before_build: 11 | - dotnet restore 12 | build: 13 | publish_nuget: false 14 | publish_nuget_symbols: false 15 | verbosity: minimal 16 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Areas/Identity/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "/Views/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/AspNetIdentityAndEFCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.0 5 | aspnet-MultiTenancyServer.Samples.AspNetIdentityAndEFCore-1B700307-89DB-47F5-B798-133F6223895F 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.Extensions.Logging; 4 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models; 5 | 6 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Controllers 7 | { 8 | public class HomeController : Controller 9 | { 10 | private readonly ILogger _logger; 11 | 12 | public HomeController(ILogger logger) 13 | { 14 | _logger = logger; 15 | } 16 | 17 | public IActionResult Index() 18 | { 19 | return View(); 20 | } 21 | 22 | public IActionResult Privacy() 23 | { 24 | return View(); 25 | } 26 | 27 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 28 | public IActionResult Error() 29 | { 30 | return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Data/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Identity; 5 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 6 | using Microsoft.EntityFrameworkCore; 7 | using Microsoft.Extensions.Logging; 8 | using MultiTenancyServer.EntityFramework; 9 | using MultiTenancyServer.Options; 10 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models; 11 | 12 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Data 13 | { 14 | public class ApplicationDbContext : IdentityDbContext, ITenantDbContext 15 | { 16 | private static TenancyModelState _tenancyModelState; 17 | private readonly ITenancyContext _tenancyContext; 18 | private readonly ILogger _logger; 19 | 20 | public ApplicationDbContext( 21 | DbContextOptions options, 22 | ITenancyContext tenancyContext, 23 | ILogger logger) 24 | : base(options) 25 | { 26 | // The request scoped tenancy context. 27 | // Should not access the tenancyContext.Tenant property in the constructor yet, 28 | // as the request pipeline has not finished running yet and it will likely be null. 29 | // Use the private property wrapper above to access it later on demand. 30 | _tenancyContext = tenancyContext; 31 | _logger = logger ?? throw new ArgumentNullException(nameof(logger)); 32 | } 33 | 34 | // MultiTenancyServer implementation. 35 | public DbSet Tenants { get; set; } 36 | 37 | protected override void OnModelCreating(ModelBuilder builder) 38 | { 39 | base.OnModelCreating(builder); 40 | // Customize the ASP.NET Identity model and override the defaults if needed. 41 | // For example, you can rename the ASP.NET Identity table names and more. 42 | // Add your customizations after calling base.OnModelCreating(builder); 43 | 44 | // MultiTenancyServer configuration. 45 | var tenantStoreOptions = new TenantStoreOptions(); 46 | builder.ConfigureTenantContext(tenantStoreOptions); 47 | 48 | // Add multi-tenancy support to model. 49 | var tenantReferenceOptions = new TenantReferenceOptions(); 50 | builder.HasTenancy(tenantReferenceOptions, out _tenancyModelState); 51 | 52 | // Configure custom properties on ApplicationTenant. 53 | builder.Entity(b => 54 | { 55 | b.Property(t => t.DisplayName).HasMaxLength(256); 56 | }); 57 | 58 | // Configure properties on User (ASP.NET Core Identity). 59 | builder.Entity(b => 60 | { 61 | // Add multi-tenancy support to entity. 62 | b.HasTenancy(() => _tenancyContext.Tenant.Id, _tenancyModelState, hasIndex: false); 63 | // Remove unique index on NormalizedUserName. 64 | b.HasIndex(u => u.NormalizedUserName).HasName("UserNameIndex").IsUnique(false); 65 | // Add unique index on TenantId and NormalizedUserName. 66 | b.HasIndex(tenantReferenceOptions.ReferenceName, nameof(ApplicationUser.NormalizedUserName)) 67 | .HasName("TenantUserNameIndex").IsUnique(); 68 | }); 69 | 70 | // Configure properties on Role (ASP.NET Core Identity). 71 | builder.Entity(b => 72 | { 73 | // Add multi-tenancy support to entity. 74 | b.HasTenancy(() => _tenancyContext.Tenant.Id, _tenancyModelState, hasIndex: false); 75 | // Remove unique index on NormalizedUserName. 76 | b.HasIndex(r => r.NormalizedName).HasName("RoleNameIndex").IsUnique(false); 77 | // Add unique index on TenantId and NormalizedUserName. 78 | b.HasIndex(tenantReferenceOptions.ReferenceName, nameof(IdentityRole.NormalizedName)) 79 | .HasName("TenantRoleNameIndex").IsUnique(); 80 | }); 81 | } 82 | 83 | public override int SaveChanges(bool acceptAllChangesOnSuccess) 84 | { 85 | // Ensure multi-tenancy for all tenantable entities. 86 | this.EnsureTenancy(_tenancyContext?.Tenant?.Id, _tenancyModelState, _logger); 87 | return base.SaveChanges(acceptAllChangesOnSuccess); 88 | } 89 | 90 | public override Task SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default) 91 | { 92 | // Ensure multi-tenancy for all tenantable entities. 93 | this.EnsureTenancy(_tenancyContext?.Tenant?.Id, _tenancyModelState, _logger); 94 | return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Data/Migrations/20191029065610_AspIdentityWithMultiTenancy.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Data; 9 | 10 | namespace AspNetIdentityAndEFCore.Migrations 11 | { 12 | [DbContext(typeof(ApplicationDbContext))] 13 | [Migration("20191029065610_AspIdentityWithMultiTenancy")] 14 | partial class AspIdentityWithMultiTenancy 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .HasAnnotation("ProductVersion", "3.0.0") 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 22 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 23 | 24 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => 25 | { 26 | b.Property("Id") 27 | .HasColumnType("nvarchar(450)"); 28 | 29 | b.Property("ConcurrencyStamp") 30 | .IsConcurrencyToken() 31 | .HasColumnType("nvarchar(max)"); 32 | 33 | b.Property("Name") 34 | .HasColumnType("nvarchar(256)") 35 | .HasMaxLength(256); 36 | 37 | b.Property("NormalizedName") 38 | .HasColumnType("nvarchar(256)") 39 | .HasMaxLength(256); 40 | 41 | b.Property("TenantId") 42 | .IsRequired() 43 | .HasColumnType("nvarchar(450)"); 44 | 45 | b.HasKey("Id"); 46 | 47 | b.HasIndex("NormalizedName") 48 | .HasName("RoleNameIndex"); 49 | 50 | b.HasIndex("TenantId", "NormalizedName") 51 | .IsUnique() 52 | .HasName("TenantRoleNameIndex") 53 | .HasFilter("[NormalizedName] IS NOT NULL"); 54 | 55 | b.ToTable("AspNetRoles"); 56 | }); 57 | 58 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 59 | { 60 | b.Property("Id") 61 | .ValueGeneratedOnAdd() 62 | .HasColumnType("int") 63 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 64 | 65 | b.Property("ClaimType") 66 | .HasColumnType("nvarchar(max)"); 67 | 68 | b.Property("ClaimValue") 69 | .HasColumnType("nvarchar(max)"); 70 | 71 | b.Property("RoleId") 72 | .IsRequired() 73 | .HasColumnType("nvarchar(450)"); 74 | 75 | b.HasKey("Id"); 76 | 77 | b.HasIndex("RoleId"); 78 | 79 | b.ToTable("AspNetRoleClaims"); 80 | }); 81 | 82 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 83 | { 84 | b.Property("Id") 85 | .ValueGeneratedOnAdd() 86 | .HasColumnType("int") 87 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 88 | 89 | b.Property("ClaimType") 90 | .HasColumnType("nvarchar(max)"); 91 | 92 | b.Property("ClaimValue") 93 | .HasColumnType("nvarchar(max)"); 94 | 95 | b.Property("UserId") 96 | .IsRequired() 97 | .HasColumnType("nvarchar(450)"); 98 | 99 | b.HasKey("Id"); 100 | 101 | b.HasIndex("UserId"); 102 | 103 | b.ToTable("AspNetUserClaims"); 104 | }); 105 | 106 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 107 | { 108 | b.Property("LoginProvider") 109 | .HasColumnType("nvarchar(128)") 110 | .HasMaxLength(128); 111 | 112 | b.Property("ProviderKey") 113 | .HasColumnType("nvarchar(128)") 114 | .HasMaxLength(128); 115 | 116 | b.Property("ProviderDisplayName") 117 | .HasColumnType("nvarchar(max)"); 118 | 119 | b.Property("UserId") 120 | .IsRequired() 121 | .HasColumnType("nvarchar(450)"); 122 | 123 | b.HasKey("LoginProvider", "ProviderKey"); 124 | 125 | b.HasIndex("UserId"); 126 | 127 | b.ToTable("AspNetUserLogins"); 128 | }); 129 | 130 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 131 | { 132 | b.Property("UserId") 133 | .HasColumnType("nvarchar(450)"); 134 | 135 | b.Property("RoleId") 136 | .HasColumnType("nvarchar(450)"); 137 | 138 | b.HasKey("UserId", "RoleId"); 139 | 140 | b.HasIndex("RoleId"); 141 | 142 | b.ToTable("AspNetUserRoles"); 143 | }); 144 | 145 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 146 | { 147 | b.Property("UserId") 148 | .HasColumnType("nvarchar(450)"); 149 | 150 | b.Property("LoginProvider") 151 | .HasColumnType("nvarchar(128)") 152 | .HasMaxLength(128); 153 | 154 | b.Property("Name") 155 | .HasColumnType("nvarchar(128)") 156 | .HasMaxLength(128); 157 | 158 | b.Property("Value") 159 | .HasColumnType("nvarchar(max)"); 160 | 161 | b.HasKey("UserId", "LoginProvider", "Name"); 162 | 163 | b.ToTable("AspNetUserTokens"); 164 | }); 165 | 166 | modelBuilder.Entity("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationTenant", b => 167 | { 168 | b.Property("Id") 169 | .HasColumnType("nvarchar(450)"); 170 | 171 | b.Property("CanonicalName") 172 | .HasColumnType("nvarchar(256)") 173 | .HasMaxLength(256); 174 | 175 | b.Property("ConcurrencyStamp") 176 | .IsConcurrencyToken() 177 | .HasColumnType("nvarchar(max)"); 178 | 179 | b.Property("DisplayName") 180 | .HasColumnType("nvarchar(256)") 181 | .HasMaxLength(256); 182 | 183 | b.Property("NormalizedCanonicalName") 184 | .HasColumnType("nvarchar(256)") 185 | .HasMaxLength(256); 186 | 187 | b.HasKey("Id"); 188 | 189 | b.HasIndex("NormalizedCanonicalName") 190 | .IsUnique() 191 | .HasName("CanonicalNameIndex") 192 | .HasFilter("[NormalizedCanonicalName] IS NOT NULL"); 193 | 194 | b.ToTable("Tenants"); 195 | }); 196 | 197 | modelBuilder.Entity("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", b => 198 | { 199 | b.Property("Id") 200 | .HasColumnType("nvarchar(450)"); 201 | 202 | b.Property("AccessFailedCount") 203 | .HasColumnType("int"); 204 | 205 | b.Property("ConcurrencyStamp") 206 | .IsConcurrencyToken() 207 | .HasColumnType("nvarchar(max)"); 208 | 209 | b.Property("Email") 210 | .HasColumnType("nvarchar(256)") 211 | .HasMaxLength(256); 212 | 213 | b.Property("EmailConfirmed") 214 | .HasColumnType("bit"); 215 | 216 | b.Property("LockoutEnabled") 217 | .HasColumnType("bit"); 218 | 219 | b.Property("LockoutEnd") 220 | .HasColumnType("datetimeoffset"); 221 | 222 | b.Property("NormalizedEmail") 223 | .HasColumnType("nvarchar(256)") 224 | .HasMaxLength(256); 225 | 226 | b.Property("NormalizedUserName") 227 | .HasColumnType("nvarchar(256)") 228 | .HasMaxLength(256); 229 | 230 | b.Property("PasswordHash") 231 | .HasColumnType("nvarchar(max)"); 232 | 233 | b.Property("PhoneNumber") 234 | .HasColumnType("nvarchar(max)"); 235 | 236 | b.Property("PhoneNumberConfirmed") 237 | .HasColumnType("bit"); 238 | 239 | b.Property("SecurityStamp") 240 | .HasColumnType("nvarchar(max)"); 241 | 242 | b.Property("TenantId") 243 | .IsRequired() 244 | .HasColumnType("nvarchar(450)"); 245 | 246 | b.Property("TwoFactorEnabled") 247 | .HasColumnType("bit"); 248 | 249 | b.Property("UserName") 250 | .HasColumnType("nvarchar(256)") 251 | .HasMaxLength(256); 252 | 253 | b.HasKey("Id"); 254 | 255 | b.HasIndex("NormalizedEmail") 256 | .HasName("EmailIndex"); 257 | 258 | b.HasIndex("NormalizedUserName") 259 | .HasName("UserNameIndex"); 260 | 261 | b.HasIndex("TenantId", "NormalizedUserName") 262 | .IsUnique() 263 | .HasName("TenantUserNameIndex") 264 | .HasFilter("[NormalizedUserName] IS NOT NULL"); 265 | 266 | b.ToTable("AspNetUsers"); 267 | }); 268 | 269 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 270 | { 271 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 272 | .WithMany() 273 | .HasForeignKey("RoleId") 274 | .OnDelete(DeleteBehavior.Cascade) 275 | .IsRequired(); 276 | }); 277 | 278 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 279 | { 280 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 281 | .WithMany() 282 | .HasForeignKey("UserId") 283 | .OnDelete(DeleteBehavior.Cascade) 284 | .IsRequired(); 285 | }); 286 | 287 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 288 | { 289 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 290 | .WithMany() 291 | .HasForeignKey("UserId") 292 | .OnDelete(DeleteBehavior.Cascade) 293 | .IsRequired(); 294 | }); 295 | 296 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 297 | { 298 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 299 | .WithMany() 300 | .HasForeignKey("RoleId") 301 | .OnDelete(DeleteBehavior.Cascade) 302 | .IsRequired(); 303 | 304 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 305 | .WithMany() 306 | .HasForeignKey("UserId") 307 | .OnDelete(DeleteBehavior.Cascade) 308 | .IsRequired(); 309 | }); 310 | 311 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 312 | { 313 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 314 | .WithMany() 315 | .HasForeignKey("UserId") 316 | .OnDelete(DeleteBehavior.Cascade) 317 | .IsRequired(); 318 | }); 319 | #pragma warning restore 612, 618 320 | } 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Data/Migrations/20191029065610_AspIdentityWithMultiTenancy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | namespace AspNetIdentityAndEFCore.Migrations 5 | { 6 | public partial class AspIdentityWithMultiTenancy : Migration 7 | { 8 | protected override void Up(MigrationBuilder migrationBuilder) 9 | { 10 | migrationBuilder.CreateTable( 11 | name: "AspNetRoles", 12 | columns: table => new 13 | { 14 | Id = table.Column(nullable: false), 15 | Name = table.Column(maxLength: 256, nullable: true), 16 | NormalizedName = table.Column(maxLength: 256, nullable: true), 17 | ConcurrencyStamp = table.Column(nullable: true), 18 | TenantId = table.Column(nullable: false) 19 | }, 20 | constraints: table => 21 | { 22 | table.PrimaryKey("PK_AspNetRoles", x => x.Id); 23 | }); 24 | 25 | migrationBuilder.CreateTable( 26 | name: "AspNetUsers", 27 | columns: table => new 28 | { 29 | Id = table.Column(nullable: false), 30 | UserName = table.Column(maxLength: 256, nullable: true), 31 | NormalizedUserName = table.Column(maxLength: 256, nullable: true), 32 | Email = table.Column(maxLength: 256, nullable: true), 33 | NormalizedEmail = table.Column(maxLength: 256, nullable: true), 34 | EmailConfirmed = table.Column(nullable: false), 35 | PasswordHash = table.Column(nullable: true), 36 | SecurityStamp = table.Column(nullable: true), 37 | ConcurrencyStamp = table.Column(nullable: true), 38 | PhoneNumber = table.Column(nullable: true), 39 | PhoneNumberConfirmed = table.Column(nullable: false), 40 | TwoFactorEnabled = table.Column(nullable: false), 41 | LockoutEnd = table.Column(nullable: true), 42 | LockoutEnabled = table.Column(nullable: false), 43 | AccessFailedCount = table.Column(nullable: false), 44 | TenantId = table.Column(nullable: false) 45 | }, 46 | constraints: table => 47 | { 48 | table.PrimaryKey("PK_AspNetUsers", x => x.Id); 49 | }); 50 | 51 | migrationBuilder.CreateTable( 52 | name: "Tenants", 53 | columns: table => new 54 | { 55 | Id = table.Column(nullable: false), 56 | CanonicalName = table.Column(maxLength: 256, nullable: true), 57 | NormalizedCanonicalName = table.Column(maxLength: 256, nullable: true), 58 | ConcurrencyStamp = table.Column(nullable: true), 59 | DisplayName = table.Column(maxLength: 256, nullable: true) 60 | }, 61 | constraints: table => 62 | { 63 | table.PrimaryKey("PK_Tenants", x => x.Id); 64 | }); 65 | 66 | migrationBuilder.CreateTable( 67 | name: "AspNetRoleClaims", 68 | columns: table => new 69 | { 70 | Id = table.Column(nullable: false) 71 | .Annotation("SqlServer:Identity", "1, 1"), 72 | RoleId = table.Column(nullable: false), 73 | ClaimType = table.Column(nullable: true), 74 | ClaimValue = table.Column(nullable: true) 75 | }, 76 | constraints: table => 77 | { 78 | table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); 79 | table.ForeignKey( 80 | name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", 81 | column: x => x.RoleId, 82 | principalTable: "AspNetRoles", 83 | principalColumn: "Id", 84 | onDelete: ReferentialAction.Cascade); 85 | }); 86 | 87 | migrationBuilder.CreateTable( 88 | name: "AspNetUserClaims", 89 | columns: table => new 90 | { 91 | Id = table.Column(nullable: false) 92 | .Annotation("SqlServer:Identity", "1, 1"), 93 | UserId = table.Column(nullable: false), 94 | ClaimType = table.Column(nullable: true), 95 | ClaimValue = table.Column(nullable: true) 96 | }, 97 | constraints: table => 98 | { 99 | table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); 100 | table.ForeignKey( 101 | name: "FK_AspNetUserClaims_AspNetUsers_UserId", 102 | column: x => x.UserId, 103 | principalTable: "AspNetUsers", 104 | principalColumn: "Id", 105 | onDelete: ReferentialAction.Cascade); 106 | }); 107 | 108 | migrationBuilder.CreateTable( 109 | name: "AspNetUserLogins", 110 | columns: table => new 111 | { 112 | LoginProvider = table.Column(maxLength: 128, nullable: false), 113 | ProviderKey = table.Column(maxLength: 128, nullable: false), 114 | ProviderDisplayName = table.Column(nullable: true), 115 | UserId = table.Column(nullable: false) 116 | }, 117 | constraints: table => 118 | { 119 | table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); 120 | table.ForeignKey( 121 | name: "FK_AspNetUserLogins_AspNetUsers_UserId", 122 | column: x => x.UserId, 123 | principalTable: "AspNetUsers", 124 | principalColumn: "Id", 125 | onDelete: ReferentialAction.Cascade); 126 | }); 127 | 128 | migrationBuilder.CreateTable( 129 | name: "AspNetUserRoles", 130 | columns: table => new 131 | { 132 | UserId = table.Column(nullable: false), 133 | RoleId = table.Column(nullable: false) 134 | }, 135 | constraints: table => 136 | { 137 | table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); 138 | table.ForeignKey( 139 | name: "FK_AspNetUserRoles_AspNetRoles_RoleId", 140 | column: x => x.RoleId, 141 | principalTable: "AspNetRoles", 142 | principalColumn: "Id", 143 | onDelete: ReferentialAction.Cascade); 144 | table.ForeignKey( 145 | name: "FK_AspNetUserRoles_AspNetUsers_UserId", 146 | column: x => x.UserId, 147 | principalTable: "AspNetUsers", 148 | principalColumn: "Id", 149 | onDelete: ReferentialAction.Cascade); 150 | }); 151 | 152 | migrationBuilder.CreateTable( 153 | name: "AspNetUserTokens", 154 | columns: table => new 155 | { 156 | UserId = table.Column(nullable: false), 157 | LoginProvider = table.Column(maxLength: 128, nullable: false), 158 | Name = table.Column(maxLength: 128, nullable: false), 159 | Value = table.Column(nullable: true) 160 | }, 161 | constraints: table => 162 | { 163 | table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); 164 | table.ForeignKey( 165 | name: "FK_AspNetUserTokens_AspNetUsers_UserId", 166 | column: x => x.UserId, 167 | principalTable: "AspNetUsers", 168 | principalColumn: "Id", 169 | onDelete: ReferentialAction.Cascade); 170 | }); 171 | 172 | migrationBuilder.CreateIndex( 173 | name: "IX_AspNetRoleClaims_RoleId", 174 | table: "AspNetRoleClaims", 175 | column: "RoleId"); 176 | 177 | migrationBuilder.CreateIndex( 178 | name: "RoleNameIndex", 179 | table: "AspNetRoles", 180 | column: "NormalizedName"); 181 | 182 | migrationBuilder.CreateIndex( 183 | name: "TenantRoleNameIndex", 184 | table: "AspNetRoles", 185 | columns: new[] { "TenantId", "NormalizedName" }, 186 | unique: true, 187 | filter: "[NormalizedName] IS NOT NULL"); 188 | 189 | migrationBuilder.CreateIndex( 190 | name: "IX_AspNetUserClaims_UserId", 191 | table: "AspNetUserClaims", 192 | column: "UserId"); 193 | 194 | migrationBuilder.CreateIndex( 195 | name: "IX_AspNetUserLogins_UserId", 196 | table: "AspNetUserLogins", 197 | column: "UserId"); 198 | 199 | migrationBuilder.CreateIndex( 200 | name: "IX_AspNetUserRoles_RoleId", 201 | table: "AspNetUserRoles", 202 | column: "RoleId"); 203 | 204 | migrationBuilder.CreateIndex( 205 | name: "EmailIndex", 206 | table: "AspNetUsers", 207 | column: "NormalizedEmail"); 208 | 209 | migrationBuilder.CreateIndex( 210 | name: "UserNameIndex", 211 | table: "AspNetUsers", 212 | column: "NormalizedUserName"); 213 | 214 | migrationBuilder.CreateIndex( 215 | name: "TenantUserNameIndex", 216 | table: "AspNetUsers", 217 | columns: new[] { "TenantId", "NormalizedUserName" }, 218 | unique: true, 219 | filter: "[NormalizedUserName] IS NOT NULL"); 220 | 221 | migrationBuilder.CreateIndex( 222 | name: "CanonicalNameIndex", 223 | table: "Tenants", 224 | column: "NormalizedCanonicalName", 225 | unique: true, 226 | filter: "[NormalizedCanonicalName] IS NOT NULL"); 227 | } 228 | 229 | protected override void Down(MigrationBuilder migrationBuilder) 230 | { 231 | migrationBuilder.DropTable( 232 | name: "AspNetRoleClaims"); 233 | 234 | migrationBuilder.DropTable( 235 | name: "AspNetUserClaims"); 236 | 237 | migrationBuilder.DropTable( 238 | name: "AspNetUserLogins"); 239 | 240 | migrationBuilder.DropTable( 241 | name: "AspNetUserRoles"); 242 | 243 | migrationBuilder.DropTable( 244 | name: "AspNetUserTokens"); 245 | 246 | migrationBuilder.DropTable( 247 | name: "Tenants"); 248 | 249 | migrationBuilder.DropTable( 250 | name: "AspNetRoles"); 251 | 252 | migrationBuilder.DropTable( 253 | name: "AspNetUsers"); 254 | } 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Data/Migrations/ApplicationDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 7 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Data; 8 | 9 | namespace AspNetIdentityAndEFCore.Migrations 10 | { 11 | [DbContext(typeof(ApplicationDbContext))] 12 | partial class ApplicationDbContextModelSnapshot : ModelSnapshot 13 | { 14 | protected override void BuildModel(ModelBuilder modelBuilder) 15 | { 16 | #pragma warning disable 612, 618 17 | modelBuilder 18 | .HasAnnotation("ProductVersion", "3.0.0") 19 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 20 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 21 | 22 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => 23 | { 24 | b.Property("Id") 25 | .HasColumnType("nvarchar(450)"); 26 | 27 | b.Property("ConcurrencyStamp") 28 | .IsConcurrencyToken() 29 | .HasColumnType("nvarchar(max)"); 30 | 31 | b.Property("Name") 32 | .HasColumnType("nvarchar(256)") 33 | .HasMaxLength(256); 34 | 35 | b.Property("NormalizedName") 36 | .HasColumnType("nvarchar(256)") 37 | .HasMaxLength(256); 38 | 39 | b.Property("TenantId") 40 | .IsRequired() 41 | .HasColumnType("nvarchar(450)"); 42 | 43 | b.HasKey("Id"); 44 | 45 | b.HasIndex("NormalizedName") 46 | .HasName("RoleNameIndex"); 47 | 48 | b.HasIndex("TenantId", "NormalizedName") 49 | .IsUnique() 50 | .HasName("TenantRoleNameIndex") 51 | .HasFilter("[NormalizedName] IS NOT NULL"); 52 | 53 | b.ToTable("AspNetRoles"); 54 | }); 55 | 56 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 57 | { 58 | b.Property("Id") 59 | .ValueGeneratedOnAdd() 60 | .HasColumnType("int") 61 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 62 | 63 | b.Property("ClaimType") 64 | .HasColumnType("nvarchar(max)"); 65 | 66 | b.Property("ClaimValue") 67 | .HasColumnType("nvarchar(max)"); 68 | 69 | b.Property("RoleId") 70 | .IsRequired() 71 | .HasColumnType("nvarchar(450)"); 72 | 73 | b.HasKey("Id"); 74 | 75 | b.HasIndex("RoleId"); 76 | 77 | b.ToTable("AspNetRoleClaims"); 78 | }); 79 | 80 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 81 | { 82 | b.Property("Id") 83 | .ValueGeneratedOnAdd() 84 | .HasColumnType("int") 85 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 86 | 87 | b.Property("ClaimType") 88 | .HasColumnType("nvarchar(max)"); 89 | 90 | b.Property("ClaimValue") 91 | .HasColumnType("nvarchar(max)"); 92 | 93 | b.Property("UserId") 94 | .IsRequired() 95 | .HasColumnType("nvarchar(450)"); 96 | 97 | b.HasKey("Id"); 98 | 99 | b.HasIndex("UserId"); 100 | 101 | b.ToTable("AspNetUserClaims"); 102 | }); 103 | 104 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 105 | { 106 | b.Property("LoginProvider") 107 | .HasColumnType("nvarchar(128)") 108 | .HasMaxLength(128); 109 | 110 | b.Property("ProviderKey") 111 | .HasColumnType("nvarchar(128)") 112 | .HasMaxLength(128); 113 | 114 | b.Property("ProviderDisplayName") 115 | .HasColumnType("nvarchar(max)"); 116 | 117 | b.Property("UserId") 118 | .IsRequired() 119 | .HasColumnType("nvarchar(450)"); 120 | 121 | b.HasKey("LoginProvider", "ProviderKey"); 122 | 123 | b.HasIndex("UserId"); 124 | 125 | b.ToTable("AspNetUserLogins"); 126 | }); 127 | 128 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 129 | { 130 | b.Property("UserId") 131 | .HasColumnType("nvarchar(450)"); 132 | 133 | b.Property("RoleId") 134 | .HasColumnType("nvarchar(450)"); 135 | 136 | b.HasKey("UserId", "RoleId"); 137 | 138 | b.HasIndex("RoleId"); 139 | 140 | b.ToTable("AspNetUserRoles"); 141 | }); 142 | 143 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 144 | { 145 | b.Property("UserId") 146 | .HasColumnType("nvarchar(450)"); 147 | 148 | b.Property("LoginProvider") 149 | .HasColumnType("nvarchar(128)") 150 | .HasMaxLength(128); 151 | 152 | b.Property("Name") 153 | .HasColumnType("nvarchar(128)") 154 | .HasMaxLength(128); 155 | 156 | b.Property("Value") 157 | .HasColumnType("nvarchar(max)"); 158 | 159 | b.HasKey("UserId", "LoginProvider", "Name"); 160 | 161 | b.ToTable("AspNetUserTokens"); 162 | }); 163 | 164 | modelBuilder.Entity("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationTenant", b => 165 | { 166 | b.Property("Id") 167 | .HasColumnType("nvarchar(450)"); 168 | 169 | b.Property("CanonicalName") 170 | .HasColumnType("nvarchar(256)") 171 | .HasMaxLength(256); 172 | 173 | b.Property("ConcurrencyStamp") 174 | .IsConcurrencyToken() 175 | .HasColumnType("nvarchar(max)"); 176 | 177 | b.Property("DisplayName") 178 | .HasColumnType("nvarchar(256)") 179 | .HasMaxLength(256); 180 | 181 | b.Property("NormalizedCanonicalName") 182 | .HasColumnType("nvarchar(256)") 183 | .HasMaxLength(256); 184 | 185 | b.HasKey("Id"); 186 | 187 | b.HasIndex("NormalizedCanonicalName") 188 | .IsUnique() 189 | .HasName("CanonicalNameIndex") 190 | .HasFilter("[NormalizedCanonicalName] IS NOT NULL"); 191 | 192 | b.ToTable("Tenants"); 193 | }); 194 | 195 | modelBuilder.Entity("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", b => 196 | { 197 | b.Property("Id") 198 | .HasColumnType("nvarchar(450)"); 199 | 200 | b.Property("AccessFailedCount") 201 | .HasColumnType("int"); 202 | 203 | b.Property("ConcurrencyStamp") 204 | .IsConcurrencyToken() 205 | .HasColumnType("nvarchar(max)"); 206 | 207 | b.Property("Email") 208 | .HasColumnType("nvarchar(256)") 209 | .HasMaxLength(256); 210 | 211 | b.Property("EmailConfirmed") 212 | .HasColumnType("bit"); 213 | 214 | b.Property("LockoutEnabled") 215 | .HasColumnType("bit"); 216 | 217 | b.Property("LockoutEnd") 218 | .HasColumnType("datetimeoffset"); 219 | 220 | b.Property("NormalizedEmail") 221 | .HasColumnType("nvarchar(256)") 222 | .HasMaxLength(256); 223 | 224 | b.Property("NormalizedUserName") 225 | .HasColumnType("nvarchar(256)") 226 | .HasMaxLength(256); 227 | 228 | b.Property("PasswordHash") 229 | .HasColumnType("nvarchar(max)"); 230 | 231 | b.Property("PhoneNumber") 232 | .HasColumnType("nvarchar(max)"); 233 | 234 | b.Property("PhoneNumberConfirmed") 235 | .HasColumnType("bit"); 236 | 237 | b.Property("SecurityStamp") 238 | .HasColumnType("nvarchar(max)"); 239 | 240 | b.Property("TenantId") 241 | .IsRequired() 242 | .HasColumnType("nvarchar(450)"); 243 | 244 | b.Property("TwoFactorEnabled") 245 | .HasColumnType("bit"); 246 | 247 | b.Property("UserName") 248 | .HasColumnType("nvarchar(256)") 249 | .HasMaxLength(256); 250 | 251 | b.HasKey("Id"); 252 | 253 | b.HasIndex("NormalizedEmail") 254 | .HasName("EmailIndex"); 255 | 256 | b.HasIndex("NormalizedUserName") 257 | .HasName("UserNameIndex"); 258 | 259 | b.HasIndex("TenantId", "NormalizedUserName") 260 | .IsUnique() 261 | .HasName("TenantUserNameIndex") 262 | .HasFilter("[NormalizedUserName] IS NOT NULL"); 263 | 264 | b.ToTable("AspNetUsers"); 265 | }); 266 | 267 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 268 | { 269 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 270 | .WithMany() 271 | .HasForeignKey("RoleId") 272 | .OnDelete(DeleteBehavior.Cascade) 273 | .IsRequired(); 274 | }); 275 | 276 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 277 | { 278 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 279 | .WithMany() 280 | .HasForeignKey("UserId") 281 | .OnDelete(DeleteBehavior.Cascade) 282 | .IsRequired(); 283 | }); 284 | 285 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 286 | { 287 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 288 | .WithMany() 289 | .HasForeignKey("UserId") 290 | .OnDelete(DeleteBehavior.Cascade) 291 | .IsRequired(); 292 | }); 293 | 294 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 295 | { 296 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 297 | .WithMany() 298 | .HasForeignKey("RoleId") 299 | .OnDelete(DeleteBehavior.Cascade) 300 | .IsRequired(); 301 | 302 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 303 | .WithMany() 304 | .HasForeignKey("UserId") 305 | .OnDelete(DeleteBehavior.Cascade) 306 | .IsRequired(); 307 | }); 308 | 309 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 310 | { 311 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 312 | .WithMany() 313 | .HasForeignKey("UserId") 314 | .OnDelete(DeleteBehavior.Cascade) 315 | .IsRequired(); 316 | }); 317 | #pragma warning restore 612, 618 318 | } 319 | } 320 | } 321 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Models/ApplicationTenant.cs: -------------------------------------------------------------------------------- 1 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models 2 | { 3 | // Add profile data for application tenants by adding properties to the ApplicationTenant class 4 | public class ApplicationTenant : TenancyTenant 5 | { 6 | public string DisplayName { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Models/ApplicationUser.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | 3 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models 4 | { 5 | // Add profile data for application users by adding properties to the ApplicationUser class 6 | public class ApplicationUser : IdentityUser 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Models/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models 4 | { 5 | public class ErrorViewModel 6 | { 7 | public string RequestId { get; set; } 8 | 9 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.Extensions.Hosting; 5 | using Serilog; 6 | using Serilog.Events; 7 | using Serilog.Sinks.SystemConsole.Themes; 8 | 9 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore 10 | { 11 | public class Program 12 | { 13 | public static void Main(string[] args) 14 | { 15 | Console.Title = "MultiTenancyServerWithAspNetIdentityAndEFCore"; 16 | 17 | Log.Logger = new LoggerConfiguration() 18 | .MinimumLevel.Debug() 19 | .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) 20 | .MinimumLevel.Override("System", LogEventLevel.Warning) 21 | .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Information) 22 | .MinimumLevel.Override("Microsoft.AspNetCore.Authentication", LogEventLevel.Information) 23 | .Enrich.FromLogContext() 24 | .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}", theme: AnsiConsoleTheme.Literate) 25 | .CreateLogger(); 26 | 27 | var seed = args.Contains("/seed"); 28 | if (seed) 29 | { 30 | args = args.Except(new[] { "/seed" }).ToArray(); 31 | } 32 | 33 | var host = CreateHostBuilder(args).Build(); 34 | 35 | if (seed) 36 | { 37 | SeedData.EnsureSeedData(host.Services); 38 | } 39 | 40 | host.Run(); 41 | } 42 | 43 | public static IHostBuilder CreateHostBuilder(string[] args) => 44 | Host.CreateDefaultBuilder(args) 45 | .ConfigureWebHostDefaults(webBuilder => 46 | { 47 | webBuilder.UseStartup(); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "AspNetIdentityAndEFCore": { 4 | "commandName": "Project", 5 | "commandLineArgs": "/seed", 6 | "launchBrowser": true, 7 | "applicationUrl": "https://tenant1.tenants.local:5000", 8 | "environmentVariables": { 9 | "ASPNETCORE_ENVIRONMENT": "Development" 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/SeedData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Data; 7 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models; 8 | 9 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore 10 | { 11 | public class SeedData 12 | { 13 | public static void EnsureSeedData(IServiceProvider serviceProvider) 14 | { 15 | Console.WriteLine("Seeding database..."); 16 | 17 | using (var scope = serviceProvider.GetRequiredService().CreateScope()) 18 | { 19 | var context = scope.ServiceProvider.GetService(); 20 | context.Database.Migrate(); 21 | 22 | var tenantMgr = scope.ServiceProvider.GetRequiredService>(); 23 | var tenant1 = tenantMgr.FindByCanonicalNameAsync("tenant1").Result; 24 | if (tenant1 == null) 25 | { 26 | tenant1 = new ApplicationTenant 27 | { 28 | CanonicalName = "tenant1", 29 | DisplayName = "Tenant One", 30 | }; 31 | var result = tenantMgr.CreateAsync(tenant1).Result; 32 | if (!result.Succeeded) 33 | { 34 | throw new Exception(result.Errors.First().Description); 35 | } 36 | 37 | Console.WriteLine("tenant1 created"); 38 | } 39 | else 40 | { 41 | Console.WriteLine("tenant1 already exists"); 42 | } 43 | 44 | var tenant2 = tenantMgr.FindByCanonicalNameAsync("tenant2").Result; 45 | if (tenant2 == null) 46 | { 47 | tenant2 = new ApplicationTenant 48 | { 49 | CanonicalName = "tenant2", 50 | DisplayName = "Tenant Two", 51 | }; 52 | var result = tenantMgr.CreateAsync(tenant2).Result; 53 | if (!result.Succeeded) 54 | { 55 | throw new Exception(result.Errors.First().Description); 56 | } 57 | 58 | Console.WriteLine("tenant2 created"); 59 | } 60 | else 61 | { 62 | Console.WriteLine("tenant2 already exists"); 63 | } 64 | } 65 | 66 | using (var scope = serviceProvider.GetRequiredService().CreateScope()) 67 | { 68 | var tenantMgr = scope.ServiceProvider.GetRequiredService>(); 69 | var tenant = tenantMgr.FindByCanonicalNameAsync("Tenant1").Result; 70 | var tenancyContext = scope.ServiceProvider.GetService>(); 71 | tenancyContext.Tenant = tenant; 72 | 73 | var context = scope.ServiceProvider.GetService(); 74 | 75 | var userMgr = scope.ServiceProvider.GetRequiredService>(); 76 | var alice = userMgr.FindByNameAsync("alice@contoso.com").Result; 77 | if (alice == null) 78 | { 79 | alice = new ApplicationUser 80 | { 81 | UserName = "alice@contoso.com", 82 | Email = "alice@contoso.com", 83 | EmailConfirmed = true 84 | }; 85 | var result = userMgr.CreateAsync(alice, "Pass123$").Result; 86 | if (!result.Succeeded) 87 | { 88 | throw new Exception(result.Errors.First().Description); 89 | } 90 | 91 | Console.WriteLine("alice created"); 92 | } 93 | else 94 | { 95 | Console.WriteLine("alice already exists"); 96 | } 97 | 98 | var bob = userMgr.FindByNameAsync("bob@contoso.com").Result; 99 | if (bob == null) 100 | { 101 | bob = new ApplicationUser 102 | { 103 | UserName = "bob@contoso.com", 104 | Email = "bob@contoso.com", 105 | EmailConfirmed = true 106 | }; 107 | var result = userMgr.CreateAsync(bob, "Pass123$").Result; 108 | if (!result.Succeeded) 109 | { 110 | throw new Exception(result.Errors.First().Description); 111 | } 112 | 113 | Console.WriteLine("bob created"); 114 | } 115 | else 116 | { 117 | Console.WriteLine("bob already exists"); 118 | } 119 | } 120 | 121 | using (var scope = serviceProvider.GetRequiredService().CreateScope()) 122 | { 123 | var tenantMgr = scope.ServiceProvider.GetRequiredService>(); 124 | var tenant = tenantMgr.FindByCanonicalNameAsync("Tenant2").Result; 125 | var tenancyContext = scope.ServiceProvider.GetService>(); 126 | tenancyContext.Tenant = tenant; 127 | 128 | var context = scope.ServiceProvider.GetService(); 129 | 130 | var userMgr = scope.ServiceProvider.GetRequiredService>(); 131 | var alice = userMgr.FindByNameAsync("alice@contoso.com").Result; 132 | if (alice == null) 133 | { 134 | alice = new ApplicationUser 135 | { 136 | UserName = "alice@contoso.com", 137 | Email = "alice@contoso.com", 138 | EmailConfirmed = true 139 | }; 140 | var result = userMgr.CreateAsync(alice, "Pass123$").Result; 141 | if (!result.Succeeded) 142 | { 143 | throw new Exception(result.Errors.First().Description); 144 | } 145 | 146 | Console.WriteLine("alice created"); 147 | } 148 | else 149 | { 150 | Console.WriteLine("alice already exists"); 151 | } 152 | 153 | var chris = userMgr.FindByNameAsync("chris@contoso.com").Result; 154 | if (chris == null) 155 | { 156 | chris = new ApplicationUser 157 | { 158 | UserName = "chris@contoso.com", 159 | Email = "chris@contoso.com", 160 | EmailConfirmed = true 161 | }; 162 | var result = userMgr.CreateAsync(chris, "Pass123$").Result; 163 | if (!result.Succeeded) 164 | { 165 | throw new Exception(result.Errors.First().Description); 166 | } 167 | 168 | Console.WriteLine("chris created"); 169 | } 170 | else 171 | { 172 | Console.WriteLine("chris already exists"); 173 | } 174 | } 175 | 176 | Console.WriteLine("Done seeding database."); 177 | Console.WriteLine(); 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Microsoft.Extensions.Hosting; 8 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Data; 9 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models; 10 | 11 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore 12 | { 13 | public class Startup 14 | { 15 | public Startup(IConfiguration configuration) 16 | { 17 | Configuration = configuration; 18 | } 19 | 20 | public IConfiguration Configuration { get; } 21 | 22 | // This method gets called by the runtime. Use this method to add services to the container. 23 | public void ConfigureServices(IServiceCollection services) 24 | { 25 | services.AddDbContext(options => 26 | options 27 | //.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")) 28 | .UseSqlite(Configuration.GetConnectionString("DefaultConnection")) 29 | .EnableSensitiveDataLogging()); 30 | services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) 31 | .AddEntityFrameworkStores(); 32 | // Add Multi-Tenancy services. 33 | services.AddMultiTenancy() 34 | // To test a domain parser locally, add a similar line 35 | // to your hosts file for each tenant you want to test 36 | // For Windows: C:\Windows\System32\drivers\etc\hosts 37 | // 127.0.0.1 tenant1.tenants.local 38 | // 127.0.0.1 tenant2.tenants.local 39 | .AddSubdomainParser(".tenants.local") 40 | .AddEntityFrameworkStore(); 41 | services.AddControllersWithViews(); 42 | services.AddRazorPages(); 43 | } 44 | 45 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 46 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 47 | { 48 | if (env.IsDevelopment()) 49 | { 50 | app.UseDeveloperExceptionPage(); 51 | app.UseDatabaseErrorPage(); 52 | } 53 | else 54 | { 55 | app.UseExceptionHandler("/Home/Error"); 56 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 57 | app.UseHsts(); 58 | } 59 | app.UseHttpsRedirection(); 60 | app.UseStaticFiles(); 61 | 62 | app.UseRouting(); 63 | 64 | app.UseMultiTenancy(); 65 | 66 | app.UseAuthentication(); 67 | app.UseAuthorization(); 68 | 69 | app.UseEndpoints(endpoints => 70 | { 71 | endpoints.MapControllerRoute( 72 | name: "default", 73 | pattern: "{controller=Home}/{action=Index}/{id?}"); 74 | endpoints.MapRazorPages(); 75 | }); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Home Page"; 3 | } 4 | 5 |
6 |

Welcome

7 |

Learn about building Web apps with ASP.NET Core.

8 |
9 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Views/Home/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Privacy Policy"; 3 | } 4 |

@ViewData["Title"]

5 | 6 |

Use this page to detail your site's privacy policy.

7 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model ErrorViewModel 2 | @{ 3 | ViewData["Title"] = "Error"; 4 | } 5 | 6 |

Error.

7 |

An error occurred while processing your request.

8 | 9 | @if (Model.ShowRequestId) 10 | { 11 |

12 | Request ID: @Model.RequestId 13 |

14 | } 15 | 16 |

Development Mode

17 |

18 | Swapping to Development environment will display more detailed information about the error that occurred. 19 |

20 |

21 | The Development environment shouldn't be enabled for deployed applications. 22 | It can result in displaying sensitive information from exceptions to end users. 23 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 24 | and restarting the app. 25 |

26 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - AspNetIdentityAndEFCore 7 | 8 | 9 | 10 | 11 |
12 | 32 |
33 |
34 |
35 | @RenderBody() 36 |
37 |
38 | 39 |
40 |
41 | © 2019 - AspNetIdentityAndEFCore - Privacy 42 |
43 |
44 | 45 | 46 | 47 | @RenderSection("Scripts", required: false) 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Views/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @inject SignInManager SignInManager 3 | @inject UserManager UserManager 4 | 5 | 27 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Views/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using MultiTenancyServer.Samples.AspNetIdentityAndEFCore 2 | @using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultConnection": "Data Source=AspUsers.db;" 4 | }, 5 | "Logging": { 6 | "LogLevel": { 7 | "Default": "Information", 8 | "Microsoft": "Warning", 9 | "Microsoft.Hosting.Lifetime": "Information" 10 | } 11 | }, 12 | "AllowedHosts": "*" 13 | } 14 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | 4 | a.navbar-brand { 5 | white-space: normal; 6 | text-align: center; 7 | word-break: break-all; 8 | } 9 | 10 | /* Provide sufficient contrast against white background */ 11 | a { 12 | color: #0366d6; 13 | } 14 | 15 | .btn-primary { 16 | color: #fff; 17 | background-color: #1b6ec2; 18 | border-color: #1861ac; 19 | } 20 | 21 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link { 22 | color: #fff; 23 | background-color: #1b6ec2; 24 | border-color: #1861ac; 25 | } 26 | 27 | /* Sticky footer styles 28 | -------------------------------------------------- */ 29 | html { 30 | font-size: 14px; 31 | } 32 | @media (min-width: 768px) { 33 | html { 34 | font-size: 16px; 35 | } 36 | } 37 | 38 | .border-top { 39 | border-top: 1px solid #e5e5e5; 40 | } 41 | .border-bottom { 42 | border-bottom: 1px solid #e5e5e5; 43 | } 44 | 45 | .box-shadow { 46 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 47 | } 48 | 49 | button.accept-policy { 50 | font-size: 1rem; 51 | line-height: inherit; 52 | } 53 | 54 | /* Sticky footer styles 55 | -------------------------------------------------- */ 56 | html { 57 | position: relative; 58 | min-height: 100%; 59 | } 60 | 61 | body { 62 | /* Margin bottom by footer height */ 63 | margin-bottom: 60px; 64 | } 65 | .footer { 66 | position: absolute; 67 | bottom: 0; 68 | width: 100%; 69 | white-space: nowrap; 70 | line-height: 60px; /* Vertically center the text there */ 71 | } 72 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MultiTenancyServer/MultiTenancyServer.Samples/ea4fc3b38356a5972909224c999b0a3f54573e10/src/AspNetIdentityAndEFCore/wwwroot/favicon.ico -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your JavaScript code. 5 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2018 Twitter, Inc. 4 | Copyright (c) 2011-2018 The Bootstrap Authors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/) 3 | * Copyright 2011-2019 The Bootstrap Authors 4 | * Copyright 2011-2019 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */ 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: border-box; 12 | } 13 | 14 | html { 15 | font-family: sans-serif; 16 | line-height: 1.15; 17 | -webkit-text-size-adjust: 100%; 18 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 19 | } 20 | 21 | article, aside, figcaption, figure, footer, header, hgroup, main, nav, section { 22 | display: block; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | 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"; 28 | font-size: 1rem; 29 | font-weight: 400; 30 | line-height: 1.5; 31 | color: #212529; 32 | text-align: left; 33 | background-color: #fff; 34 | } 35 | 36 | [tabindex="-1"]:focus { 37 | outline: 0 !important; 38 | } 39 | 40 | hr { 41 | box-sizing: content-box; 42 | height: 0; 43 | overflow: visible; 44 | } 45 | 46 | h1, h2, h3, h4, h5, h6 { 47 | margin-top: 0; 48 | margin-bottom: 0.5rem; 49 | } 50 | 51 | p { 52 | margin-top: 0; 53 | margin-bottom: 1rem; 54 | } 55 | 56 | abbr[title], 57 | abbr[data-original-title] { 58 | text-decoration: underline; 59 | -webkit-text-decoration: underline dotted; 60 | text-decoration: underline dotted; 61 | cursor: help; 62 | border-bottom: 0; 63 | -webkit-text-decoration-skip-ink: none; 64 | text-decoration-skip-ink: none; 65 | } 66 | 67 | address { 68 | margin-bottom: 1rem; 69 | font-style: normal; 70 | line-height: inherit; 71 | } 72 | 73 | ol, 74 | ul, 75 | dl { 76 | margin-top: 0; 77 | margin-bottom: 1rem; 78 | } 79 | 80 | ol ol, 81 | ul ul, 82 | ol ul, 83 | ul ol { 84 | margin-bottom: 0; 85 | } 86 | 87 | dt { 88 | font-weight: 700; 89 | } 90 | 91 | dd { 92 | margin-bottom: .5rem; 93 | margin-left: 0; 94 | } 95 | 96 | blockquote { 97 | margin: 0 0 1rem; 98 | } 99 | 100 | b, 101 | strong { 102 | font-weight: bolder; 103 | } 104 | 105 | small { 106 | font-size: 80%; 107 | } 108 | 109 | sub, 110 | sup { 111 | position: relative; 112 | font-size: 75%; 113 | line-height: 0; 114 | vertical-align: baseline; 115 | } 116 | 117 | sub { 118 | bottom: -.25em; 119 | } 120 | 121 | sup { 122 | top: -.5em; 123 | } 124 | 125 | a { 126 | color: #007bff; 127 | text-decoration: none; 128 | background-color: transparent; 129 | } 130 | 131 | a:hover { 132 | color: #0056b3; 133 | text-decoration: underline; 134 | } 135 | 136 | a:not([href]):not([tabindex]) { 137 | color: inherit; 138 | text-decoration: none; 139 | } 140 | 141 | a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus { 142 | color: inherit; 143 | text-decoration: none; 144 | } 145 | 146 | a:not([href]):not([tabindex]):focus { 147 | outline: 0; 148 | } 149 | 150 | pre, 151 | code, 152 | kbd, 153 | samp { 154 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 155 | font-size: 1em; 156 | } 157 | 158 | pre { 159 | margin-top: 0; 160 | margin-bottom: 1rem; 161 | overflow: auto; 162 | } 163 | 164 | figure { 165 | margin: 0 0 1rem; 166 | } 167 | 168 | img { 169 | vertical-align: middle; 170 | border-style: none; 171 | } 172 | 173 | svg { 174 | overflow: hidden; 175 | vertical-align: middle; 176 | } 177 | 178 | table { 179 | border-collapse: collapse; 180 | } 181 | 182 | caption { 183 | padding-top: 0.75rem; 184 | padding-bottom: 0.75rem; 185 | color: #6c757d; 186 | text-align: left; 187 | caption-side: bottom; 188 | } 189 | 190 | th { 191 | text-align: inherit; 192 | } 193 | 194 | label { 195 | display: inline-block; 196 | margin-bottom: 0.5rem; 197 | } 198 | 199 | button { 200 | border-radius: 0; 201 | } 202 | 203 | button:focus { 204 | outline: 1px dotted; 205 | outline: 5px auto -webkit-focus-ring-color; 206 | } 207 | 208 | input, 209 | button, 210 | select, 211 | optgroup, 212 | textarea { 213 | margin: 0; 214 | font-family: inherit; 215 | font-size: inherit; 216 | line-height: inherit; 217 | } 218 | 219 | button, 220 | input { 221 | overflow: visible; 222 | } 223 | 224 | button, 225 | select { 226 | text-transform: none; 227 | } 228 | 229 | select { 230 | word-wrap: normal; 231 | } 232 | 233 | button, 234 | [type="button"], 235 | [type="reset"], 236 | [type="submit"] { 237 | -webkit-appearance: button; 238 | } 239 | 240 | button:not(:disabled), 241 | [type="button"]:not(:disabled), 242 | [type="reset"]:not(:disabled), 243 | [type="submit"]:not(:disabled) { 244 | cursor: pointer; 245 | } 246 | 247 | button::-moz-focus-inner, 248 | [type="button"]::-moz-focus-inner, 249 | [type="reset"]::-moz-focus-inner, 250 | [type="submit"]::-moz-focus-inner { 251 | padding: 0; 252 | border-style: none; 253 | } 254 | 255 | input[type="radio"], 256 | input[type="checkbox"] { 257 | box-sizing: border-box; 258 | padding: 0; 259 | } 260 | 261 | input[type="date"], 262 | input[type="time"], 263 | input[type="datetime-local"], 264 | input[type="month"] { 265 | -webkit-appearance: listbox; 266 | } 267 | 268 | textarea { 269 | overflow: auto; 270 | resize: vertical; 271 | } 272 | 273 | fieldset { 274 | min-width: 0; 275 | padding: 0; 276 | margin: 0; 277 | border: 0; 278 | } 279 | 280 | legend { 281 | display: block; 282 | width: 100%; 283 | max-width: 100%; 284 | padding: 0; 285 | margin-bottom: .5rem; 286 | font-size: 1.5rem; 287 | line-height: inherit; 288 | color: inherit; 289 | white-space: normal; 290 | } 291 | 292 | progress { 293 | vertical-align: baseline; 294 | } 295 | 296 | [type="number"]::-webkit-inner-spin-button, 297 | [type="number"]::-webkit-outer-spin-button { 298 | height: auto; 299 | } 300 | 301 | [type="search"] { 302 | outline-offset: -2px; 303 | -webkit-appearance: none; 304 | } 305 | 306 | [type="search"]::-webkit-search-decoration { 307 | -webkit-appearance: none; 308 | } 309 | 310 | ::-webkit-file-upload-button { 311 | font: inherit; 312 | -webkit-appearance: button; 313 | } 314 | 315 | output { 316 | display: inline-block; 317 | } 318 | 319 | summary { 320 | display: list-item; 321 | cursor: pointer; 322 | } 323 | 324 | template { 325 | display: none; 326 | } 327 | 328 | [hidden] { 329 | display: none !important; 330 | } 331 | /*# sourceMappingURL=bootstrap-reboot.css.map */ -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/) 3 | * Copyright 2011-2019 The Bootstrap Authors 4 | * Copyright 2011-2019 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */*,::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} 8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */ -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) .NET Foundation. All rights reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | these files except in compliance with the License. You may obtain a copy of the 5 | License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed 10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | // Unobtrusive validation support library for jQuery and jQuery Validate 2 | // Copyright (c) .NET Foundation. All rights reserved. 3 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 4 | // @version v3.2.11 5 | !function(a){"function"==typeof define&&define.amd?define("jquery.validate.unobtrusive",["jquery-validation"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery-validation")):jQuery.validator.unobtrusive=a(jQuery)}(function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("
  • ").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function u(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=f.unobtrusive.options||{},u=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),u("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),u("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),u("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var m,f=a.validator,v="unobtrusiveValidation";return f.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=u(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){f.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=u(this);a&&a.attachValidation()})}},m=f.unobtrusive.adapters,m.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},m.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},m.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},m.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},f.addMethod("__dummy__",function(a,e,n){return!0}),f.addMethod("regex",function(a,e,n){var t;return!!this.optional(e)||(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),f.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),f.methods.extension?(m.addSingleVal("accept","mimtype"),m.addSingleVal("extension","extension")):m.addSingleVal("extension","extension","accept"),m.addSingleVal("regex","pattern"),m.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),m.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),m.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),m.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),m.add("required",function(a){"INPUT"===a.element.tagName.toUpperCase()&&"CHECKBOX"===a.element.type.toUpperCase()||e(a,"required",!0)}),m.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),m.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),m.add("fileextensions",["extensions"],function(a){e(a,"extension",a.params.extensions)}),a(function(){f.unobtrusive.parse(document)}),f.unobtrusive}); -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/AspNetIdentityAndEFCore/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright JS Foundation and other contributors, https://js.foundation/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | All files located in the node_modules and external directories are 34 | externally maintained libraries used by this software which have their 35 | own licenses; we recommend you read them, as their terms may differ from 36 | the terms above. 37 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Areas/Identity/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "/Views/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.Extensions.Logging; 4 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models; 5 | 6 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Controllers 7 | { 8 | public class HomeController : Controller 9 | { 10 | private readonly ILogger _logger; 11 | 12 | public HomeController(ILogger logger) 13 | { 14 | _logger = logger; 15 | } 16 | 17 | public IActionResult Index() 18 | { 19 | return View(); 20 | } 21 | 22 | public IActionResult Privacy() 23 | { 24 | return View(); 25 | } 26 | 27 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 28 | public IActionResult Error() 29 | { 30 | return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Data/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Identity; 5 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 6 | using Microsoft.EntityFrameworkCore; 7 | using Microsoft.Extensions.Logging; 8 | using MultiTenancyServer.EntityFramework; 9 | using MultiTenancyServer.Options; 10 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models; 11 | 12 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Data 13 | { 14 | public class ApplicationDbContext : IdentityDbContext, long>, ITenantDbContext 15 | { 16 | private static TenancyModelState _tenancyModelState; 17 | private readonly ITenancyContext _tenancyContext; 18 | private readonly ILogger _logger; 19 | 20 | public ApplicationDbContext( 21 | DbContextOptions options, 22 | ITenancyContext tenancyContext, 23 | ILogger logger) 24 | : base(options) 25 | { 26 | // The request scoped tenancy context. 27 | // Should not access the tenancyContext.Tenant property in the constructor yet, 28 | // as the request pipeline has not finished running yet and it will likely be null. 29 | // Use the private property wrapper above to access it later on demand. 30 | _tenancyContext = tenancyContext; 31 | _logger = logger ?? throw new ArgumentNullException(nameof(logger)); 32 | } 33 | 34 | // MultiTenancyServer implementation. 35 | public DbSet Tenants { get; set; } 36 | 37 | protected override void OnModelCreating(ModelBuilder builder) 38 | { 39 | base.OnModelCreating(builder); 40 | // Customize the ASP.NET Identity model and override the defaults if needed. 41 | // For example, you can rename the ASP.NET Identity table names and more. 42 | // Add your customizations after calling base.OnModelCreating(builder); 43 | 44 | // MultiTenancyServer configuration. 45 | var tenantStoreOptions = new TenantStoreOptions(); 46 | builder.ConfigureTenantContext(tenantStoreOptions); 47 | 48 | // Add multi-tenancy support to model. 49 | var tenantReferenceOptions = new TenantReferenceOptions(); 50 | builder.HasTenancy(tenantReferenceOptions, out _tenancyModelState); 51 | 52 | // Configure custom properties on ApplicationTenant. 53 | builder.Entity(b => 54 | { 55 | b.Property(t => t.DisplayName).HasMaxLength(256); 56 | }); 57 | 58 | // Configure properties on User (ASP.NET Core Identity). 59 | builder.Entity(b => 60 | { 61 | // Add multi-tenancy support to entity. 62 | b.HasTenancy(() => _tenancyContext.Tenant.Id, _tenancyModelState, hasIndex: false); 63 | // Remove unique index on NormalizedUserName. 64 | b.HasIndex(u => u.NormalizedUserName).HasName("UserNameIndex").IsUnique(false); 65 | // Add unique index on TenantId and NormalizedUserName. 66 | b.HasIndex(tenantReferenceOptions.ReferenceName, nameof(ApplicationUser.NormalizedUserName)) 67 | .HasName("TenantUserNameIndex").IsUnique(); 68 | }); 69 | 70 | // Configure properties on Role (ASP.NET Core Identity). 71 | builder.Entity>(b => 72 | { 73 | // Add multi-tenancy support to entity. 74 | b.HasTenancy(() => _tenancyContext.Tenant.Id, _tenancyModelState, hasIndex: false); 75 | // Remove unique index on NormalizedUserName. 76 | b.HasIndex(r => r.NormalizedName).HasName("RoleNameIndex").IsUnique(false); 77 | // Add unique index on TenantId and NormalizedUserName. 78 | b.HasIndex(tenantReferenceOptions.ReferenceName, nameof(IdentityRole.NormalizedName)) 79 | .HasName("TenantRoleNameIndex").IsUnique(); 80 | }); 81 | } 82 | 83 | public override int SaveChanges(bool acceptAllChangesOnSuccess) 84 | { 85 | // Ensure multi-tenancy for all tenantable entities. 86 | this.EnsureTenancy(_tenancyContext?.Tenant?.Id, _tenancyModelState, _logger); 87 | return base.SaveChanges(acceptAllChangesOnSuccess); 88 | } 89 | 90 | public override Task SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default) 91 | { 92 | // Ensure multi-tenancy for all tenantable entities. 93 | this.EnsureTenancy(_tenancyContext?.Tenant?.Id, _tenancyModelState, _logger); 94 | return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Data/Migrations/20191029065621_AspIdentityWithMultiTenancy.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Data; 9 | 10 | namespace Int64AspNetIdentityAndEFCore.Migrations 11 | { 12 | [DbContext(typeof(ApplicationDbContext))] 13 | [Migration("20191029065621_AspIdentityWithMultiTenancy")] 14 | partial class AspIdentityWithMultiTenancy 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .HasAnnotation("ProductVersion", "3.0.0") 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 22 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 23 | 24 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => 25 | { 26 | b.Property("Id") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("bigint") 29 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 30 | 31 | b.Property("ConcurrencyStamp") 32 | .IsConcurrencyToken() 33 | .HasColumnType("nvarchar(max)"); 34 | 35 | b.Property("Name") 36 | .HasColumnType("nvarchar(256)") 37 | .HasMaxLength(256); 38 | 39 | b.Property("NormalizedName") 40 | .HasColumnType("nvarchar(256)") 41 | .HasMaxLength(256); 42 | 43 | b.Property("TenantId") 44 | .HasColumnType("bigint"); 45 | 46 | b.HasKey("Id"); 47 | 48 | b.HasIndex("NormalizedName") 49 | .HasName("RoleNameIndex"); 50 | 51 | b.HasIndex("TenantId", "NormalizedName") 52 | .IsUnique() 53 | .HasName("TenantRoleNameIndex") 54 | .HasFilter("[NormalizedName] IS NOT NULL"); 55 | 56 | b.ToTable("AspNetRoles"); 57 | }); 58 | 59 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 60 | { 61 | b.Property("Id") 62 | .ValueGeneratedOnAdd() 63 | .HasColumnType("int") 64 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 65 | 66 | b.Property("ClaimType") 67 | .HasColumnType("nvarchar(max)"); 68 | 69 | b.Property("ClaimValue") 70 | .HasColumnType("nvarchar(max)"); 71 | 72 | b.Property("RoleId") 73 | .HasColumnType("bigint"); 74 | 75 | b.HasKey("Id"); 76 | 77 | b.HasIndex("RoleId"); 78 | 79 | b.ToTable("AspNetRoleClaims"); 80 | }); 81 | 82 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 83 | { 84 | b.Property("Id") 85 | .ValueGeneratedOnAdd() 86 | .HasColumnType("int") 87 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 88 | 89 | b.Property("ClaimType") 90 | .HasColumnType("nvarchar(max)"); 91 | 92 | b.Property("ClaimValue") 93 | .HasColumnType("nvarchar(max)"); 94 | 95 | b.Property("UserId") 96 | .HasColumnType("bigint"); 97 | 98 | b.HasKey("Id"); 99 | 100 | b.HasIndex("UserId"); 101 | 102 | b.ToTable("AspNetUserClaims"); 103 | }); 104 | 105 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 106 | { 107 | b.Property("LoginProvider") 108 | .HasColumnType("nvarchar(128)") 109 | .HasMaxLength(128); 110 | 111 | b.Property("ProviderKey") 112 | .HasColumnType("nvarchar(128)") 113 | .HasMaxLength(128); 114 | 115 | b.Property("ProviderDisplayName") 116 | .HasColumnType("nvarchar(max)"); 117 | 118 | b.Property("UserId") 119 | .HasColumnType("bigint"); 120 | 121 | b.HasKey("LoginProvider", "ProviderKey"); 122 | 123 | b.HasIndex("UserId"); 124 | 125 | b.ToTable("AspNetUserLogins"); 126 | }); 127 | 128 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 129 | { 130 | b.Property("UserId") 131 | .HasColumnType("bigint"); 132 | 133 | b.Property("RoleId") 134 | .HasColumnType("bigint"); 135 | 136 | b.HasKey("UserId", "RoleId"); 137 | 138 | b.HasIndex("RoleId"); 139 | 140 | b.ToTable("AspNetUserRoles"); 141 | }); 142 | 143 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 144 | { 145 | b.Property("UserId") 146 | .HasColumnType("bigint"); 147 | 148 | b.Property("LoginProvider") 149 | .HasColumnType("nvarchar(128)") 150 | .HasMaxLength(128); 151 | 152 | b.Property("Name") 153 | .HasColumnType("nvarchar(128)") 154 | .HasMaxLength(128); 155 | 156 | b.Property("Value") 157 | .HasColumnType("nvarchar(max)"); 158 | 159 | b.HasKey("UserId", "LoginProvider", "Name"); 160 | 161 | b.ToTable("AspNetUserTokens"); 162 | }); 163 | 164 | modelBuilder.Entity("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationTenant", b => 165 | { 166 | b.Property("Id") 167 | .ValueGeneratedOnAdd() 168 | .HasColumnType("bigint") 169 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 170 | 171 | b.Property("CanonicalName") 172 | .HasColumnType("nvarchar(256)") 173 | .HasMaxLength(256); 174 | 175 | b.Property("ConcurrencyStamp") 176 | .IsConcurrencyToken() 177 | .HasColumnType("nvarchar(max)"); 178 | 179 | b.Property("DisplayName") 180 | .HasColumnType("nvarchar(256)") 181 | .HasMaxLength(256); 182 | 183 | b.Property("NormalizedCanonicalName") 184 | .HasColumnType("nvarchar(256)") 185 | .HasMaxLength(256); 186 | 187 | b.HasKey("Id"); 188 | 189 | b.HasIndex("NormalizedCanonicalName") 190 | .IsUnique() 191 | .HasName("CanonicalNameIndex") 192 | .HasFilter("[NormalizedCanonicalName] IS NOT NULL"); 193 | 194 | b.ToTable("Tenants"); 195 | }); 196 | 197 | modelBuilder.Entity("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", b => 198 | { 199 | b.Property("Id") 200 | .ValueGeneratedOnAdd() 201 | .HasColumnType("bigint") 202 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 203 | 204 | b.Property("AccessFailedCount") 205 | .HasColumnType("int"); 206 | 207 | b.Property("ConcurrencyStamp") 208 | .IsConcurrencyToken() 209 | .HasColumnType("nvarchar(max)"); 210 | 211 | b.Property("Email") 212 | .HasColumnType("nvarchar(256)") 213 | .HasMaxLength(256); 214 | 215 | b.Property("EmailConfirmed") 216 | .HasColumnType("bit"); 217 | 218 | b.Property("LockoutEnabled") 219 | .HasColumnType("bit"); 220 | 221 | b.Property("LockoutEnd") 222 | .HasColumnType("datetimeoffset"); 223 | 224 | b.Property("NormalizedEmail") 225 | .HasColumnType("nvarchar(256)") 226 | .HasMaxLength(256); 227 | 228 | b.Property("NormalizedUserName") 229 | .HasColumnType("nvarchar(256)") 230 | .HasMaxLength(256); 231 | 232 | b.Property("PasswordHash") 233 | .HasColumnType("nvarchar(max)"); 234 | 235 | b.Property("PhoneNumber") 236 | .HasColumnType("nvarchar(max)"); 237 | 238 | b.Property("PhoneNumberConfirmed") 239 | .HasColumnType("bit"); 240 | 241 | b.Property("SecurityStamp") 242 | .HasColumnType("nvarchar(max)"); 243 | 244 | b.Property("TenantId") 245 | .HasColumnType("bigint"); 246 | 247 | b.Property("TwoFactorEnabled") 248 | .HasColumnType("bit"); 249 | 250 | b.Property("UserName") 251 | .HasColumnType("nvarchar(256)") 252 | .HasMaxLength(256); 253 | 254 | b.HasKey("Id"); 255 | 256 | b.HasIndex("NormalizedEmail") 257 | .HasName("EmailIndex"); 258 | 259 | b.HasIndex("NormalizedUserName") 260 | .HasName("UserNameIndex"); 261 | 262 | b.HasIndex("TenantId", "NormalizedUserName") 263 | .IsUnique() 264 | .HasName("TenantUserNameIndex") 265 | .HasFilter("[NormalizedUserName] IS NOT NULL"); 266 | 267 | b.ToTable("AspNetUsers"); 268 | }); 269 | 270 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 271 | { 272 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 273 | .WithMany() 274 | .HasForeignKey("RoleId") 275 | .OnDelete(DeleteBehavior.Cascade) 276 | .IsRequired(); 277 | }); 278 | 279 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 280 | { 281 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 282 | .WithMany() 283 | .HasForeignKey("UserId") 284 | .OnDelete(DeleteBehavior.Cascade) 285 | .IsRequired(); 286 | }); 287 | 288 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 289 | { 290 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 291 | .WithMany() 292 | .HasForeignKey("UserId") 293 | .OnDelete(DeleteBehavior.Cascade) 294 | .IsRequired(); 295 | }); 296 | 297 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 298 | { 299 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 300 | .WithMany() 301 | .HasForeignKey("RoleId") 302 | .OnDelete(DeleteBehavior.Cascade) 303 | .IsRequired(); 304 | 305 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 306 | .WithMany() 307 | .HasForeignKey("UserId") 308 | .OnDelete(DeleteBehavior.Cascade) 309 | .IsRequired(); 310 | }); 311 | 312 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 313 | { 314 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 315 | .WithMany() 316 | .HasForeignKey("UserId") 317 | .OnDelete(DeleteBehavior.Cascade) 318 | .IsRequired(); 319 | }); 320 | #pragma warning restore 612, 618 321 | } 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Data/Migrations/20191029065621_AspIdentityWithMultiTenancy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | namespace Int64AspNetIdentityAndEFCore.Migrations 5 | { 6 | public partial class AspIdentityWithMultiTenancy : Migration 7 | { 8 | protected override void Up(MigrationBuilder migrationBuilder) 9 | { 10 | migrationBuilder.CreateTable( 11 | name: "AspNetRoles", 12 | columns: table => new 13 | { 14 | Id = table.Column(nullable: false) 15 | .Annotation("SqlServer:Identity", "1, 1"), 16 | Name = table.Column(maxLength: 256, nullable: true), 17 | NormalizedName = table.Column(maxLength: 256, nullable: true), 18 | ConcurrencyStamp = table.Column(nullable: true), 19 | TenantId = table.Column(nullable: false) 20 | }, 21 | constraints: table => 22 | { 23 | table.PrimaryKey("PK_AspNetRoles", x => x.Id); 24 | }); 25 | 26 | migrationBuilder.CreateTable( 27 | name: "AspNetUsers", 28 | columns: table => new 29 | { 30 | Id = table.Column(nullable: false) 31 | .Annotation("SqlServer:Identity", "1, 1"), 32 | UserName = table.Column(maxLength: 256, nullable: true), 33 | NormalizedUserName = table.Column(maxLength: 256, nullable: true), 34 | Email = table.Column(maxLength: 256, nullable: true), 35 | NormalizedEmail = table.Column(maxLength: 256, nullable: true), 36 | EmailConfirmed = table.Column(nullable: false), 37 | PasswordHash = table.Column(nullable: true), 38 | SecurityStamp = table.Column(nullable: true), 39 | ConcurrencyStamp = table.Column(nullable: true), 40 | PhoneNumber = table.Column(nullable: true), 41 | PhoneNumberConfirmed = table.Column(nullable: false), 42 | TwoFactorEnabled = table.Column(nullable: false), 43 | LockoutEnd = table.Column(nullable: true), 44 | LockoutEnabled = table.Column(nullable: false), 45 | AccessFailedCount = table.Column(nullable: false), 46 | TenantId = table.Column(nullable: false) 47 | }, 48 | constraints: table => 49 | { 50 | table.PrimaryKey("PK_AspNetUsers", x => x.Id); 51 | }); 52 | 53 | migrationBuilder.CreateTable( 54 | name: "Tenants", 55 | columns: table => new 56 | { 57 | Id = table.Column(nullable: false) 58 | .Annotation("SqlServer:Identity", "1, 1"), 59 | CanonicalName = table.Column(maxLength: 256, nullable: true), 60 | NormalizedCanonicalName = table.Column(maxLength: 256, nullable: true), 61 | ConcurrencyStamp = table.Column(nullable: true), 62 | DisplayName = table.Column(maxLength: 256, nullable: true) 63 | }, 64 | constraints: table => 65 | { 66 | table.PrimaryKey("PK_Tenants", x => x.Id); 67 | }); 68 | 69 | migrationBuilder.CreateTable( 70 | name: "AspNetRoleClaims", 71 | columns: table => new 72 | { 73 | Id = table.Column(nullable: false) 74 | .Annotation("SqlServer:Identity", "1, 1"), 75 | RoleId = table.Column(nullable: false), 76 | ClaimType = table.Column(nullable: true), 77 | ClaimValue = table.Column(nullable: true) 78 | }, 79 | constraints: table => 80 | { 81 | table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); 82 | table.ForeignKey( 83 | name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", 84 | column: x => x.RoleId, 85 | principalTable: "AspNetRoles", 86 | principalColumn: "Id", 87 | onDelete: ReferentialAction.Cascade); 88 | }); 89 | 90 | migrationBuilder.CreateTable( 91 | name: "AspNetUserClaims", 92 | columns: table => new 93 | { 94 | Id = table.Column(nullable: false) 95 | .Annotation("SqlServer:Identity", "1, 1"), 96 | UserId = table.Column(nullable: false), 97 | ClaimType = table.Column(nullable: true), 98 | ClaimValue = table.Column(nullable: true) 99 | }, 100 | constraints: table => 101 | { 102 | table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); 103 | table.ForeignKey( 104 | name: "FK_AspNetUserClaims_AspNetUsers_UserId", 105 | column: x => x.UserId, 106 | principalTable: "AspNetUsers", 107 | principalColumn: "Id", 108 | onDelete: ReferentialAction.Cascade); 109 | }); 110 | 111 | migrationBuilder.CreateTable( 112 | name: "AspNetUserLogins", 113 | columns: table => new 114 | { 115 | LoginProvider = table.Column(maxLength: 128, nullable: false), 116 | ProviderKey = table.Column(maxLength: 128, nullable: false), 117 | ProviderDisplayName = table.Column(nullable: true), 118 | UserId = table.Column(nullable: false) 119 | }, 120 | constraints: table => 121 | { 122 | table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); 123 | table.ForeignKey( 124 | name: "FK_AspNetUserLogins_AspNetUsers_UserId", 125 | column: x => x.UserId, 126 | principalTable: "AspNetUsers", 127 | principalColumn: "Id", 128 | onDelete: ReferentialAction.Cascade); 129 | }); 130 | 131 | migrationBuilder.CreateTable( 132 | name: "AspNetUserRoles", 133 | columns: table => new 134 | { 135 | UserId = table.Column(nullable: false), 136 | RoleId = table.Column(nullable: false) 137 | }, 138 | constraints: table => 139 | { 140 | table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); 141 | table.ForeignKey( 142 | name: "FK_AspNetUserRoles_AspNetRoles_RoleId", 143 | column: x => x.RoleId, 144 | principalTable: "AspNetRoles", 145 | principalColumn: "Id", 146 | onDelete: ReferentialAction.Cascade); 147 | table.ForeignKey( 148 | name: "FK_AspNetUserRoles_AspNetUsers_UserId", 149 | column: x => x.UserId, 150 | principalTable: "AspNetUsers", 151 | principalColumn: "Id", 152 | onDelete: ReferentialAction.Cascade); 153 | }); 154 | 155 | migrationBuilder.CreateTable( 156 | name: "AspNetUserTokens", 157 | columns: table => new 158 | { 159 | UserId = table.Column(nullable: false), 160 | LoginProvider = table.Column(maxLength: 128, nullable: false), 161 | Name = table.Column(maxLength: 128, nullable: false), 162 | Value = table.Column(nullable: true) 163 | }, 164 | constraints: table => 165 | { 166 | table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); 167 | table.ForeignKey( 168 | name: "FK_AspNetUserTokens_AspNetUsers_UserId", 169 | column: x => x.UserId, 170 | principalTable: "AspNetUsers", 171 | principalColumn: "Id", 172 | onDelete: ReferentialAction.Cascade); 173 | }); 174 | 175 | migrationBuilder.CreateIndex( 176 | name: "IX_AspNetRoleClaims_RoleId", 177 | table: "AspNetRoleClaims", 178 | column: "RoleId"); 179 | 180 | migrationBuilder.CreateIndex( 181 | name: "RoleNameIndex", 182 | table: "AspNetRoles", 183 | column: "NormalizedName"); 184 | 185 | migrationBuilder.CreateIndex( 186 | name: "TenantRoleNameIndex", 187 | table: "AspNetRoles", 188 | columns: new[] { "TenantId", "NormalizedName" }, 189 | unique: true, 190 | filter: "[NormalizedName] IS NOT NULL"); 191 | 192 | migrationBuilder.CreateIndex( 193 | name: "IX_AspNetUserClaims_UserId", 194 | table: "AspNetUserClaims", 195 | column: "UserId"); 196 | 197 | migrationBuilder.CreateIndex( 198 | name: "IX_AspNetUserLogins_UserId", 199 | table: "AspNetUserLogins", 200 | column: "UserId"); 201 | 202 | migrationBuilder.CreateIndex( 203 | name: "IX_AspNetUserRoles_RoleId", 204 | table: "AspNetUserRoles", 205 | column: "RoleId"); 206 | 207 | migrationBuilder.CreateIndex( 208 | name: "EmailIndex", 209 | table: "AspNetUsers", 210 | column: "NormalizedEmail"); 211 | 212 | migrationBuilder.CreateIndex( 213 | name: "UserNameIndex", 214 | table: "AspNetUsers", 215 | column: "NormalizedUserName"); 216 | 217 | migrationBuilder.CreateIndex( 218 | name: "TenantUserNameIndex", 219 | table: "AspNetUsers", 220 | columns: new[] { "TenantId", "NormalizedUserName" }, 221 | unique: true, 222 | filter: "[NormalizedUserName] IS NOT NULL"); 223 | 224 | migrationBuilder.CreateIndex( 225 | name: "CanonicalNameIndex", 226 | table: "Tenants", 227 | column: "NormalizedCanonicalName", 228 | unique: true, 229 | filter: "[NormalizedCanonicalName] IS NOT NULL"); 230 | } 231 | 232 | protected override void Down(MigrationBuilder migrationBuilder) 233 | { 234 | migrationBuilder.DropTable( 235 | name: "AspNetRoleClaims"); 236 | 237 | migrationBuilder.DropTable( 238 | name: "AspNetUserClaims"); 239 | 240 | migrationBuilder.DropTable( 241 | name: "AspNetUserLogins"); 242 | 243 | migrationBuilder.DropTable( 244 | name: "AspNetUserRoles"); 245 | 246 | migrationBuilder.DropTable( 247 | name: "AspNetUserTokens"); 248 | 249 | migrationBuilder.DropTable( 250 | name: "Tenants"); 251 | 252 | migrationBuilder.DropTable( 253 | name: "AspNetRoles"); 254 | 255 | migrationBuilder.DropTable( 256 | name: "AspNetUsers"); 257 | } 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Data/Migrations/ApplicationDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 7 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Data; 8 | 9 | namespace Int64AspNetIdentityAndEFCore.Migrations 10 | { 11 | [DbContext(typeof(ApplicationDbContext))] 12 | partial class ApplicationDbContextModelSnapshot : ModelSnapshot 13 | { 14 | protected override void BuildModel(ModelBuilder modelBuilder) 15 | { 16 | #pragma warning disable 612, 618 17 | modelBuilder 18 | .HasAnnotation("ProductVersion", "3.0.0") 19 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 20 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 21 | 22 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => 23 | { 24 | b.Property("Id") 25 | .ValueGeneratedOnAdd() 26 | .HasColumnType("bigint") 27 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 28 | 29 | b.Property("ConcurrencyStamp") 30 | .IsConcurrencyToken() 31 | .HasColumnType("nvarchar(max)"); 32 | 33 | b.Property("Name") 34 | .HasColumnType("nvarchar(256)") 35 | .HasMaxLength(256); 36 | 37 | b.Property("NormalizedName") 38 | .HasColumnType("nvarchar(256)") 39 | .HasMaxLength(256); 40 | 41 | b.Property("TenantId") 42 | .HasColumnType("bigint"); 43 | 44 | b.HasKey("Id"); 45 | 46 | b.HasIndex("NormalizedName") 47 | .HasName("RoleNameIndex"); 48 | 49 | b.HasIndex("TenantId", "NormalizedName") 50 | .IsUnique() 51 | .HasName("TenantRoleNameIndex") 52 | .HasFilter("[NormalizedName] IS NOT NULL"); 53 | 54 | b.ToTable("AspNetRoles"); 55 | }); 56 | 57 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 58 | { 59 | b.Property("Id") 60 | .ValueGeneratedOnAdd() 61 | .HasColumnType("int") 62 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 63 | 64 | b.Property("ClaimType") 65 | .HasColumnType("nvarchar(max)"); 66 | 67 | b.Property("ClaimValue") 68 | .HasColumnType("nvarchar(max)"); 69 | 70 | b.Property("RoleId") 71 | .HasColumnType("bigint"); 72 | 73 | b.HasKey("Id"); 74 | 75 | b.HasIndex("RoleId"); 76 | 77 | b.ToTable("AspNetRoleClaims"); 78 | }); 79 | 80 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 81 | { 82 | b.Property("Id") 83 | .ValueGeneratedOnAdd() 84 | .HasColumnType("int") 85 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 86 | 87 | b.Property("ClaimType") 88 | .HasColumnType("nvarchar(max)"); 89 | 90 | b.Property("ClaimValue") 91 | .HasColumnType("nvarchar(max)"); 92 | 93 | b.Property("UserId") 94 | .HasColumnType("bigint"); 95 | 96 | b.HasKey("Id"); 97 | 98 | b.HasIndex("UserId"); 99 | 100 | b.ToTable("AspNetUserClaims"); 101 | }); 102 | 103 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 104 | { 105 | b.Property("LoginProvider") 106 | .HasColumnType("nvarchar(128)") 107 | .HasMaxLength(128); 108 | 109 | b.Property("ProviderKey") 110 | .HasColumnType("nvarchar(128)") 111 | .HasMaxLength(128); 112 | 113 | b.Property("ProviderDisplayName") 114 | .HasColumnType("nvarchar(max)"); 115 | 116 | b.Property("UserId") 117 | .HasColumnType("bigint"); 118 | 119 | b.HasKey("LoginProvider", "ProviderKey"); 120 | 121 | b.HasIndex("UserId"); 122 | 123 | b.ToTable("AspNetUserLogins"); 124 | }); 125 | 126 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 127 | { 128 | b.Property("UserId") 129 | .HasColumnType("bigint"); 130 | 131 | b.Property("RoleId") 132 | .HasColumnType("bigint"); 133 | 134 | b.HasKey("UserId", "RoleId"); 135 | 136 | b.HasIndex("RoleId"); 137 | 138 | b.ToTable("AspNetUserRoles"); 139 | }); 140 | 141 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 142 | { 143 | b.Property("UserId") 144 | .HasColumnType("bigint"); 145 | 146 | b.Property("LoginProvider") 147 | .HasColumnType("nvarchar(128)") 148 | .HasMaxLength(128); 149 | 150 | b.Property("Name") 151 | .HasColumnType("nvarchar(128)") 152 | .HasMaxLength(128); 153 | 154 | b.Property("Value") 155 | .HasColumnType("nvarchar(max)"); 156 | 157 | b.HasKey("UserId", "LoginProvider", "Name"); 158 | 159 | b.ToTable("AspNetUserTokens"); 160 | }); 161 | 162 | modelBuilder.Entity("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationTenant", b => 163 | { 164 | b.Property("Id") 165 | .ValueGeneratedOnAdd() 166 | .HasColumnType("bigint") 167 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 168 | 169 | b.Property("CanonicalName") 170 | .HasColumnType("nvarchar(256)") 171 | .HasMaxLength(256); 172 | 173 | b.Property("ConcurrencyStamp") 174 | .IsConcurrencyToken() 175 | .HasColumnType("nvarchar(max)"); 176 | 177 | b.Property("DisplayName") 178 | .HasColumnType("nvarchar(256)") 179 | .HasMaxLength(256); 180 | 181 | b.Property("NormalizedCanonicalName") 182 | .HasColumnType("nvarchar(256)") 183 | .HasMaxLength(256); 184 | 185 | b.HasKey("Id"); 186 | 187 | b.HasIndex("NormalizedCanonicalName") 188 | .IsUnique() 189 | .HasName("CanonicalNameIndex") 190 | .HasFilter("[NormalizedCanonicalName] IS NOT NULL"); 191 | 192 | b.ToTable("Tenants"); 193 | }); 194 | 195 | modelBuilder.Entity("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", b => 196 | { 197 | b.Property("Id") 198 | .ValueGeneratedOnAdd() 199 | .HasColumnType("bigint") 200 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 201 | 202 | b.Property("AccessFailedCount") 203 | .HasColumnType("int"); 204 | 205 | b.Property("ConcurrencyStamp") 206 | .IsConcurrencyToken() 207 | .HasColumnType("nvarchar(max)"); 208 | 209 | b.Property("Email") 210 | .HasColumnType("nvarchar(256)") 211 | .HasMaxLength(256); 212 | 213 | b.Property("EmailConfirmed") 214 | .HasColumnType("bit"); 215 | 216 | b.Property("LockoutEnabled") 217 | .HasColumnType("bit"); 218 | 219 | b.Property("LockoutEnd") 220 | .HasColumnType("datetimeoffset"); 221 | 222 | b.Property("NormalizedEmail") 223 | .HasColumnType("nvarchar(256)") 224 | .HasMaxLength(256); 225 | 226 | b.Property("NormalizedUserName") 227 | .HasColumnType("nvarchar(256)") 228 | .HasMaxLength(256); 229 | 230 | b.Property("PasswordHash") 231 | .HasColumnType("nvarchar(max)"); 232 | 233 | b.Property("PhoneNumber") 234 | .HasColumnType("nvarchar(max)"); 235 | 236 | b.Property("PhoneNumberConfirmed") 237 | .HasColumnType("bit"); 238 | 239 | b.Property("SecurityStamp") 240 | .HasColumnType("nvarchar(max)"); 241 | 242 | b.Property("TenantId") 243 | .HasColumnType("bigint"); 244 | 245 | b.Property("TwoFactorEnabled") 246 | .HasColumnType("bit"); 247 | 248 | b.Property("UserName") 249 | .HasColumnType("nvarchar(256)") 250 | .HasMaxLength(256); 251 | 252 | b.HasKey("Id"); 253 | 254 | b.HasIndex("NormalizedEmail") 255 | .HasName("EmailIndex"); 256 | 257 | b.HasIndex("NormalizedUserName") 258 | .HasName("UserNameIndex"); 259 | 260 | b.HasIndex("TenantId", "NormalizedUserName") 261 | .IsUnique() 262 | .HasName("TenantUserNameIndex") 263 | .HasFilter("[NormalizedUserName] IS NOT NULL"); 264 | 265 | b.ToTable("AspNetUsers"); 266 | }); 267 | 268 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 269 | { 270 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 271 | .WithMany() 272 | .HasForeignKey("RoleId") 273 | .OnDelete(DeleteBehavior.Cascade) 274 | .IsRequired(); 275 | }); 276 | 277 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 278 | { 279 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 280 | .WithMany() 281 | .HasForeignKey("UserId") 282 | .OnDelete(DeleteBehavior.Cascade) 283 | .IsRequired(); 284 | }); 285 | 286 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 287 | { 288 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 289 | .WithMany() 290 | .HasForeignKey("UserId") 291 | .OnDelete(DeleteBehavior.Cascade) 292 | .IsRequired(); 293 | }); 294 | 295 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 296 | { 297 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 298 | .WithMany() 299 | .HasForeignKey("RoleId") 300 | .OnDelete(DeleteBehavior.Cascade) 301 | .IsRequired(); 302 | 303 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 304 | .WithMany() 305 | .HasForeignKey("UserId") 306 | .OnDelete(DeleteBehavior.Cascade) 307 | .IsRequired(); 308 | }); 309 | 310 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 311 | { 312 | b.HasOne("MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models.ApplicationUser", null) 313 | .WithMany() 314 | .HasForeignKey("UserId") 315 | .OnDelete(DeleteBehavior.Cascade) 316 | .IsRequired(); 317 | }); 318 | #pragma warning restore 612, 618 319 | } 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Int64AspNetIdentityAndEFCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.0 5 | aspnet-MultiTenancyServer.Samples.AspNetIdentityAndEFCore-1B700307-89DB-47F5-B798-133F6223895F 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Models/ApplicationTenant.cs: -------------------------------------------------------------------------------- 1 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models 2 | { 3 | // Add profile data for application tenants by adding properties to the ApplicationTenant class 4 | public class ApplicationTenant : TenancyTenant 5 | { 6 | public string DisplayName { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Models/ApplicationUser.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | 3 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models 4 | { 5 | // Add profile data for application users by adding properties to the ApplicationUser class 6 | public class ApplicationUser : IdentityUser 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Models/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models 4 | { 5 | public class ErrorViewModel 6 | { 7 | public string RequestId { get; set; } 8 | 9 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.Extensions.Hosting; 5 | using Serilog; 6 | using Serilog.Events; 7 | using Serilog.Sinks.SystemConsole.Themes; 8 | 9 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore 10 | { 11 | public class Program 12 | { 13 | public static void Main(string[] args) 14 | { 15 | Console.Title = "MultiTenancyServerWithAspNetIdentityAndEFCore"; 16 | 17 | Log.Logger = new LoggerConfiguration() 18 | .MinimumLevel.Debug() 19 | .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) 20 | .MinimumLevel.Override("System", LogEventLevel.Warning) 21 | .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Information) 22 | .MinimumLevel.Override("Microsoft.AspNetCore.Authentication", LogEventLevel.Information) 23 | .Enrich.FromLogContext() 24 | .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}", theme: AnsiConsoleTheme.Literate) 25 | .CreateLogger(); 26 | 27 | var seed = args.Contains("/seed"); 28 | if (seed) 29 | { 30 | args = args.Except(new[] { "/seed" }).ToArray(); 31 | } 32 | 33 | var host = CreateHostBuilder(args).Build(); 34 | 35 | if (seed) 36 | { 37 | SeedData.EnsureSeedData(host.Services); 38 | } 39 | 40 | host.Run(); 41 | } 42 | 43 | public static IHostBuilder CreateHostBuilder(string[] args) => 44 | Host.CreateDefaultBuilder(args) 45 | .ConfigureWebHostDefaults(webBuilder => 46 | { 47 | webBuilder.UseStartup(); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "AspNetIdentityAndEFCore": { 4 | "commandName": "Project", 5 | "commandLineArgs": "/seed", 6 | "launchBrowser": true, 7 | "applicationUrl": "https://tenant1.tenants.local:5000", 8 | "environmentVariables": { 9 | "ASPNETCORE_ENVIRONMENT": "Development" 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/SeedData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Data; 7 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models; 8 | 9 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore 10 | { 11 | public class SeedData 12 | { 13 | public static void EnsureSeedData(IServiceProvider serviceProvider) 14 | { 15 | Console.WriteLine("Seeding database..."); 16 | 17 | using (var scope = serviceProvider.GetRequiredService().CreateScope()) 18 | { 19 | var context = scope.ServiceProvider.GetService(); 20 | context.Database.Migrate(); 21 | 22 | var tenantMgr = scope.ServiceProvider.GetRequiredService>(); 23 | var tenant1 = tenantMgr.FindByCanonicalNameAsync("tenant1").Result; 24 | if (tenant1 == null) 25 | { 26 | tenant1 = new ApplicationTenant 27 | { 28 | CanonicalName = "tenant1", 29 | DisplayName = "Tenant One", 30 | }; 31 | var result = tenantMgr.CreateAsync(tenant1).Result; 32 | if (!result.Succeeded) 33 | { 34 | throw new Exception(result.Errors.First().Description); 35 | } 36 | 37 | Console.WriteLine("tenant1 created"); 38 | } 39 | else 40 | { 41 | Console.WriteLine("tenant1 already exists"); 42 | } 43 | 44 | var tenant2 = tenantMgr.FindByCanonicalNameAsync("tenant2").Result; 45 | if (tenant2 == null) 46 | { 47 | tenant2 = new ApplicationTenant 48 | { 49 | CanonicalName = "tenant2", 50 | DisplayName = "Tenant Two", 51 | }; 52 | var result = tenantMgr.CreateAsync(tenant2).Result; 53 | if (!result.Succeeded) 54 | { 55 | throw new Exception(result.Errors.First().Description); 56 | } 57 | 58 | Console.WriteLine("tenant2 created"); 59 | } 60 | else 61 | { 62 | Console.WriteLine("tenant2 already exists"); 63 | } 64 | } 65 | 66 | using (var scope = serviceProvider.GetRequiredService().CreateScope()) 67 | { 68 | var tenantMgr = scope.ServiceProvider.GetRequiredService>(); 69 | var tenant = tenantMgr.FindByCanonicalNameAsync("Tenant1").Result; 70 | var tenancyContext = scope.ServiceProvider.GetService>(); 71 | tenancyContext.Tenant = tenant; 72 | 73 | var context = scope.ServiceProvider.GetService(); 74 | 75 | var userMgr = scope.ServiceProvider.GetRequiredService>(); 76 | var alice = userMgr.FindByNameAsync("alice@contoso.com").Result; 77 | if (alice == null) 78 | { 79 | alice = new ApplicationUser 80 | { 81 | UserName = "alice@contoso.com", 82 | Email = "alice@contoso.com", 83 | EmailConfirmed = true 84 | }; 85 | var result = userMgr.CreateAsync(alice, "Pass123$").Result; 86 | if (!result.Succeeded) 87 | { 88 | throw new Exception(result.Errors.First().Description); 89 | } 90 | 91 | Console.WriteLine("alice created"); 92 | } 93 | else 94 | { 95 | Console.WriteLine("alice already exists"); 96 | } 97 | 98 | var bob = userMgr.FindByNameAsync("bob@contoso.com").Result; 99 | if (bob == null) 100 | { 101 | bob = new ApplicationUser 102 | { 103 | UserName = "bob@contoso.com", 104 | Email = "bob@contoso.com", 105 | EmailConfirmed = true 106 | }; 107 | var result = userMgr.CreateAsync(bob, "Pass123$").Result; 108 | if (!result.Succeeded) 109 | { 110 | throw new Exception(result.Errors.First().Description); 111 | } 112 | 113 | Console.WriteLine("bob created"); 114 | } 115 | else 116 | { 117 | Console.WriteLine("bob already exists"); 118 | } 119 | } 120 | 121 | using (var scope = serviceProvider.GetRequiredService().CreateScope()) 122 | { 123 | var tenantMgr = scope.ServiceProvider.GetRequiredService>(); 124 | var tenant = tenantMgr.FindByCanonicalNameAsync("Tenant2").Result; 125 | var tenancyContext = scope.ServiceProvider.GetService>(); 126 | tenancyContext.Tenant = tenant; 127 | 128 | var context = scope.ServiceProvider.GetService(); 129 | 130 | var userMgr = scope.ServiceProvider.GetRequiredService>(); 131 | var alice = userMgr.FindByNameAsync("alice@contoso.com").Result; 132 | if (alice == null) 133 | { 134 | alice = new ApplicationUser 135 | { 136 | UserName = "alice@contoso.com", 137 | Email = "alice@contoso.com", 138 | EmailConfirmed = true 139 | }; 140 | var result = userMgr.CreateAsync(alice, "Pass123$").Result; 141 | if (!result.Succeeded) 142 | { 143 | throw new Exception(result.Errors.First().Description); 144 | } 145 | 146 | Console.WriteLine("alice created"); 147 | } 148 | else 149 | { 150 | Console.WriteLine("alice already exists"); 151 | } 152 | 153 | var chris = userMgr.FindByNameAsync("chris@contoso.com").Result; 154 | if (chris == null) 155 | { 156 | chris = new ApplicationUser 157 | { 158 | UserName = "chris@contoso.com", 159 | Email = "chris@contoso.com", 160 | EmailConfirmed = true 161 | }; 162 | var result = userMgr.CreateAsync(chris, "Pass123$").Result; 163 | if (!result.Succeeded) 164 | { 165 | throw new Exception(result.Errors.First().Description); 166 | } 167 | 168 | Console.WriteLine("chris created"); 169 | } 170 | else 171 | { 172 | Console.WriteLine("chris already exists"); 173 | } 174 | } 175 | 176 | Console.WriteLine("Done seeding database."); 177 | Console.WriteLine(); 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Microsoft.Extensions.Hosting; 8 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Data; 9 | using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models; 10 | 11 | namespace MultiTenancyServer.Samples.AspNetIdentityAndEFCore 12 | { 13 | public class Startup 14 | { 15 | public Startup(IConfiguration configuration) 16 | { 17 | Configuration = configuration; 18 | } 19 | 20 | public IConfiguration Configuration { get; } 21 | 22 | // This method gets called by the runtime. Use this method to add services to the container. 23 | public void ConfigureServices(IServiceCollection services) 24 | { 25 | services.AddDbContext(options => 26 | options 27 | //.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")) 28 | .UseSqlite(Configuration.GetConnectionString("DefaultConnection")) 29 | .EnableSensitiveDataLogging()); 30 | services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) 31 | .AddEntityFrameworkStores(); 32 | // Add Multi-Tenancy services. 33 | services.AddMultiTenancy() 34 | // To test a domain parser locally, add a similar line 35 | // to your hosts file for each tenant you want to test 36 | // For Windows: C:\Windows\System32\drivers\etc\hosts 37 | // 127.0.0.1 tenant1.tenants.local 38 | // 127.0.0.1 tenant2.tenants.local 39 | .AddSubdomainParser(".tenants.local") 40 | .AddEntityFrameworkStore(); 41 | services.AddControllersWithViews(); 42 | services.AddRazorPages(); 43 | } 44 | 45 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 46 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 47 | { 48 | if (env.IsDevelopment()) 49 | { 50 | app.UseDeveloperExceptionPage(); 51 | app.UseDatabaseErrorPage(); 52 | } 53 | else 54 | { 55 | app.UseExceptionHandler("/Home/Error"); 56 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 57 | app.UseHsts(); 58 | } 59 | app.UseHttpsRedirection(); 60 | app.UseStaticFiles(); 61 | 62 | app.UseRouting(); 63 | 64 | app.UseMultiTenancy(); 65 | 66 | app.UseAuthentication(); 67 | app.UseAuthorization(); 68 | 69 | app.UseEndpoints(endpoints => 70 | { 71 | endpoints.MapControllerRoute( 72 | name: "default", 73 | pattern: "{controller=Home}/{action=Index}/{id?}"); 74 | endpoints.MapRazorPages(); 75 | }); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Home Page"; 3 | } 4 | 5 |
    6 |

    Welcome

    7 |

    Learn about building Web apps with ASP.NET Core.

    8 |
    9 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Views/Home/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Privacy Policy"; 3 | } 4 |

    @ViewData["Title"]

    5 | 6 |

    Use this page to detail your site's privacy policy.

    7 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model ErrorViewModel 2 | @{ 3 | ViewData["Title"] = "Error"; 4 | } 5 | 6 |

    Error.

    7 |

    An error occurred while processing your request.

    8 | 9 | @if (Model.ShowRequestId) 10 | { 11 |

    12 | Request ID: @Model.RequestId 13 |

    14 | } 15 | 16 |

    Development Mode

    17 |

    18 | Swapping to Development environment will display more detailed information about the error that occurred. 19 |

    20 |

    21 | The Development environment shouldn't be enabled for deployed applications. 22 | It can result in displaying sensitive information from exceptions to end users. 23 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 24 | and restarting the app. 25 |

    26 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - AspNetIdentityAndEFCore 7 | 8 | 9 | 10 | 11 |
    12 | 32 |
    33 |
    34 |
    35 | @RenderBody() 36 |
    37 |
    38 | 39 |
    40 |
    41 | © 2019 - AspNetIdentityAndEFCore - Privacy 42 |
    43 |
    44 | 45 | 46 | 47 | @RenderSection("Scripts", required: false) 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Views/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @inject SignInManager SignInManager 3 | @inject UserManager UserManager 4 | 5 | 27 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Views/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using MultiTenancyServer.Samples.AspNetIdentityAndEFCore 2 | @using MultiTenancyServer.Samples.AspNetIdentityAndEFCore.Models 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultConnection": "Data Source=AspUsers.db;" 4 | }, 5 | "Logging": { 6 | "LogLevel": { 7 | "Default": "Information", 8 | "Microsoft": "Warning", 9 | "Microsoft.Hosting.Lifetime": "Information" 10 | } 11 | }, 12 | "AllowedHosts": "*" 13 | } 14 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | 4 | a.navbar-brand { 5 | white-space: normal; 6 | text-align: center; 7 | word-break: break-all; 8 | } 9 | 10 | /* Provide sufficient contrast against white background */ 11 | a { 12 | color: #0366d6; 13 | } 14 | 15 | .btn-primary { 16 | color: #fff; 17 | background-color: #1b6ec2; 18 | border-color: #1861ac; 19 | } 20 | 21 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link { 22 | color: #fff; 23 | background-color: #1b6ec2; 24 | border-color: #1861ac; 25 | } 26 | 27 | /* Sticky footer styles 28 | -------------------------------------------------- */ 29 | html { 30 | font-size: 14px; 31 | } 32 | @media (min-width: 768px) { 33 | html { 34 | font-size: 16px; 35 | } 36 | } 37 | 38 | .border-top { 39 | border-top: 1px solid #e5e5e5; 40 | } 41 | .border-bottom { 42 | border-bottom: 1px solid #e5e5e5; 43 | } 44 | 45 | .box-shadow { 46 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 47 | } 48 | 49 | button.accept-policy { 50 | font-size: 1rem; 51 | line-height: inherit; 52 | } 53 | 54 | /* Sticky footer styles 55 | -------------------------------------------------- */ 56 | html { 57 | position: relative; 58 | min-height: 100%; 59 | } 60 | 61 | body { 62 | /* Margin bottom by footer height */ 63 | margin-bottom: 60px; 64 | } 65 | .footer { 66 | position: absolute; 67 | bottom: 0; 68 | width: 100%; 69 | white-space: nowrap; 70 | line-height: 60px; /* Vertically center the text there */ 71 | } 72 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MultiTenancyServer/MultiTenancyServer.Samples/ea4fc3b38356a5972909224c999b0a3f54573e10/src/Int64AspNetIdentityAndEFCore/wwwroot/favicon.ico -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your JavaScript code. 5 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2018 Twitter, Inc. 4 | Copyright (c) 2011-2018 The Bootstrap Authors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/) 3 | * Copyright 2011-2019 The Bootstrap Authors 4 | * Copyright 2011-2019 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */ 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: border-box; 12 | } 13 | 14 | html { 15 | font-family: sans-serif; 16 | line-height: 1.15; 17 | -webkit-text-size-adjust: 100%; 18 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 19 | } 20 | 21 | article, aside, figcaption, figure, footer, header, hgroup, main, nav, section { 22 | display: block; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | 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"; 28 | font-size: 1rem; 29 | font-weight: 400; 30 | line-height: 1.5; 31 | color: #212529; 32 | text-align: left; 33 | background-color: #fff; 34 | } 35 | 36 | [tabindex="-1"]:focus { 37 | outline: 0 !important; 38 | } 39 | 40 | hr { 41 | box-sizing: content-box; 42 | height: 0; 43 | overflow: visible; 44 | } 45 | 46 | h1, h2, h3, h4, h5, h6 { 47 | margin-top: 0; 48 | margin-bottom: 0.5rem; 49 | } 50 | 51 | p { 52 | margin-top: 0; 53 | margin-bottom: 1rem; 54 | } 55 | 56 | abbr[title], 57 | abbr[data-original-title] { 58 | text-decoration: underline; 59 | -webkit-text-decoration: underline dotted; 60 | text-decoration: underline dotted; 61 | cursor: help; 62 | border-bottom: 0; 63 | -webkit-text-decoration-skip-ink: none; 64 | text-decoration-skip-ink: none; 65 | } 66 | 67 | address { 68 | margin-bottom: 1rem; 69 | font-style: normal; 70 | line-height: inherit; 71 | } 72 | 73 | ol, 74 | ul, 75 | dl { 76 | margin-top: 0; 77 | margin-bottom: 1rem; 78 | } 79 | 80 | ol ol, 81 | ul ul, 82 | ol ul, 83 | ul ol { 84 | margin-bottom: 0; 85 | } 86 | 87 | dt { 88 | font-weight: 700; 89 | } 90 | 91 | dd { 92 | margin-bottom: .5rem; 93 | margin-left: 0; 94 | } 95 | 96 | blockquote { 97 | margin: 0 0 1rem; 98 | } 99 | 100 | b, 101 | strong { 102 | font-weight: bolder; 103 | } 104 | 105 | small { 106 | font-size: 80%; 107 | } 108 | 109 | sub, 110 | sup { 111 | position: relative; 112 | font-size: 75%; 113 | line-height: 0; 114 | vertical-align: baseline; 115 | } 116 | 117 | sub { 118 | bottom: -.25em; 119 | } 120 | 121 | sup { 122 | top: -.5em; 123 | } 124 | 125 | a { 126 | color: #007bff; 127 | text-decoration: none; 128 | background-color: transparent; 129 | } 130 | 131 | a:hover { 132 | color: #0056b3; 133 | text-decoration: underline; 134 | } 135 | 136 | a:not([href]):not([tabindex]) { 137 | color: inherit; 138 | text-decoration: none; 139 | } 140 | 141 | a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus { 142 | color: inherit; 143 | text-decoration: none; 144 | } 145 | 146 | a:not([href]):not([tabindex]):focus { 147 | outline: 0; 148 | } 149 | 150 | pre, 151 | code, 152 | kbd, 153 | samp { 154 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 155 | font-size: 1em; 156 | } 157 | 158 | pre { 159 | margin-top: 0; 160 | margin-bottom: 1rem; 161 | overflow: auto; 162 | } 163 | 164 | figure { 165 | margin: 0 0 1rem; 166 | } 167 | 168 | img { 169 | vertical-align: middle; 170 | border-style: none; 171 | } 172 | 173 | svg { 174 | overflow: hidden; 175 | vertical-align: middle; 176 | } 177 | 178 | table { 179 | border-collapse: collapse; 180 | } 181 | 182 | caption { 183 | padding-top: 0.75rem; 184 | padding-bottom: 0.75rem; 185 | color: #6c757d; 186 | text-align: left; 187 | caption-side: bottom; 188 | } 189 | 190 | th { 191 | text-align: inherit; 192 | } 193 | 194 | label { 195 | display: inline-block; 196 | margin-bottom: 0.5rem; 197 | } 198 | 199 | button { 200 | border-radius: 0; 201 | } 202 | 203 | button:focus { 204 | outline: 1px dotted; 205 | outline: 5px auto -webkit-focus-ring-color; 206 | } 207 | 208 | input, 209 | button, 210 | select, 211 | optgroup, 212 | textarea { 213 | margin: 0; 214 | font-family: inherit; 215 | font-size: inherit; 216 | line-height: inherit; 217 | } 218 | 219 | button, 220 | input { 221 | overflow: visible; 222 | } 223 | 224 | button, 225 | select { 226 | text-transform: none; 227 | } 228 | 229 | select { 230 | word-wrap: normal; 231 | } 232 | 233 | button, 234 | [type="button"], 235 | [type="reset"], 236 | [type="submit"] { 237 | -webkit-appearance: button; 238 | } 239 | 240 | button:not(:disabled), 241 | [type="button"]:not(:disabled), 242 | [type="reset"]:not(:disabled), 243 | [type="submit"]:not(:disabled) { 244 | cursor: pointer; 245 | } 246 | 247 | button::-moz-focus-inner, 248 | [type="button"]::-moz-focus-inner, 249 | [type="reset"]::-moz-focus-inner, 250 | [type="submit"]::-moz-focus-inner { 251 | padding: 0; 252 | border-style: none; 253 | } 254 | 255 | input[type="radio"], 256 | input[type="checkbox"] { 257 | box-sizing: border-box; 258 | padding: 0; 259 | } 260 | 261 | input[type="date"], 262 | input[type="time"], 263 | input[type="datetime-local"], 264 | input[type="month"] { 265 | -webkit-appearance: listbox; 266 | } 267 | 268 | textarea { 269 | overflow: auto; 270 | resize: vertical; 271 | } 272 | 273 | fieldset { 274 | min-width: 0; 275 | padding: 0; 276 | margin: 0; 277 | border: 0; 278 | } 279 | 280 | legend { 281 | display: block; 282 | width: 100%; 283 | max-width: 100%; 284 | padding: 0; 285 | margin-bottom: .5rem; 286 | font-size: 1.5rem; 287 | line-height: inherit; 288 | color: inherit; 289 | white-space: normal; 290 | } 291 | 292 | progress { 293 | vertical-align: baseline; 294 | } 295 | 296 | [type="number"]::-webkit-inner-spin-button, 297 | [type="number"]::-webkit-outer-spin-button { 298 | height: auto; 299 | } 300 | 301 | [type="search"] { 302 | outline-offset: -2px; 303 | -webkit-appearance: none; 304 | } 305 | 306 | [type="search"]::-webkit-search-decoration { 307 | -webkit-appearance: none; 308 | } 309 | 310 | ::-webkit-file-upload-button { 311 | font: inherit; 312 | -webkit-appearance: button; 313 | } 314 | 315 | output { 316 | display: inline-block; 317 | } 318 | 319 | summary { 320 | display: list-item; 321 | cursor: pointer; 322 | } 323 | 324 | template { 325 | display: none; 326 | } 327 | 328 | [hidden] { 329 | display: none !important; 330 | } 331 | /*# sourceMappingURL=bootstrap-reboot.css.map */ -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/) 3 | * Copyright 2011-2019 The Bootstrap Authors 4 | * Copyright 2011-2019 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */*,::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} 8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */ -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) .NET Foundation. All rights reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | these files except in compliance with the License. You may obtain a copy of the 5 | License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed 10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | // Unobtrusive validation support library for jQuery and jQuery Validate 2 | // Copyright (c) .NET Foundation. All rights reserved. 3 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 4 | // @version v3.2.11 5 | !function(a){"function"==typeof define&&define.amd?define("jquery.validate.unobtrusive",["jquery-validation"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery-validation")):jQuery.validator.unobtrusive=a(jQuery)}(function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("
  • ").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function u(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=f.unobtrusive.options||{},u=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),u("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),u("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),u("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var m,f=a.validator,v="unobtrusiveValidation";return f.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=u(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){f.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=u(this);a&&a.attachValidation()})}},m=f.unobtrusive.adapters,m.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},m.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},m.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},m.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},f.addMethod("__dummy__",function(a,e,n){return!0}),f.addMethod("regex",function(a,e,n){var t;return!!this.optional(e)||(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),f.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),f.methods.extension?(m.addSingleVal("accept","mimtype"),m.addSingleVal("extension","extension")):m.addSingleVal("extension","extension","accept"),m.addSingleVal("regex","pattern"),m.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),m.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),m.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),m.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),m.add("required",function(a){"INPUT"===a.element.tagName.toUpperCase()&&"CHECKBOX"===a.element.type.toUpperCase()||e(a,"required",!0)}),m.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),m.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),m.add("fileextensions",["extensions"],function(a){e(a,"extension",a.params.extensions)}),a(function(){f.unobtrusive.parse(document)}),f.unobtrusive}); -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/Int64AspNetIdentityAndEFCore/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright JS Foundation and other contributors, https://js.foundation/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | All files located in the node_modules and external directories are 34 | externally maintained libraries used by this software which have their 35 | own licenses; we recommend you read them, as their terms may differ from 36 | the terms above. 37 | --------------------------------------------------------------------------------