├── .gitattributes ├── .gitignore ├── ChatApplication.sln ├── ChatApplication ├── App_Start │ ├── BundleConfig.cs │ ├── FilterConfig.cs │ ├── IdentityConfig.cs │ ├── RouteConfig.cs │ └── Startup.Auth.cs ├── ChatApplication.csproj ├── Content │ ├── Site.css │ ├── bootstrap.css │ └── bootstrap.min.css ├── Controllers │ ├── AccountController.cs │ ├── HomeController.cs │ └── ManageController.cs ├── Global.asax ├── Global.asax.cs ├── Hubs │ └── ChatHub.cs ├── Models │ ├── AccountViewModels.cs │ ├── IdentityModels.cs │ └── ManageViewModels.cs ├── Project_Readme.html ├── Properties │ ├── AssemblyInfo.cs │ └── PublishProfiles │ │ └── XamarinChat - Web Deploy.pubxml ├── Scripts │ ├── _references.js │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── jquery-2.1.4.intellisense.js │ ├── jquery-2.1.4.js │ ├── jquery-2.1.4.min.js │ ├── jquery-2.1.4.min.map │ ├── jquery.signalR-2.2.0.js │ ├── jquery.signalR-2.2.0.min.js │ ├── jquery.validate-vsdoc.js │ ├── jquery.validate.js │ ├── jquery.validate.min.js │ ├── jquery.validate.unobtrusive.js │ ├── jquery.validate.unobtrusive.min.js │ ├── modernizr-2.6.2.js │ ├── respond.js │ └── respond.min.js ├── Startup.cs ├── Views │ ├── Account │ │ ├── ConfirmEmail.cshtml │ │ ├── ExternalLoginConfirmation.cshtml │ │ ├── ExternalLoginFailure.cshtml │ │ ├── ForgotPassword.cshtml │ │ ├── ForgotPasswordConfirmation.cshtml │ │ ├── Login.cshtml │ │ ├── Register.cshtml │ │ ├── ResetPassword.cshtml │ │ ├── ResetPasswordConfirmation.cshtml │ │ ├── SendCode.cshtml │ │ ├── VerifyCode.cshtml │ │ └── _ExternalLoginsListPartial.cshtml │ ├── Home │ │ ├── About.cshtml │ │ ├── Chat.cshtml │ │ ├── Contact.cshtml │ │ └── Index.cshtml │ ├── Manage │ │ ├── AddPhoneNumber.cshtml │ │ ├── ChangePassword.cshtml │ │ ├── Index.cshtml │ │ ├── ManageLogins.cshtml │ │ ├── SetPassword.cshtml │ │ └── VerifyPhoneNumber.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ ├── Lockout.cshtml │ │ ├── _Layout.cshtml │ │ └── _LoginPartial.cshtml │ ├── Web.config │ └── _ViewStart.cshtml ├── Web.Debug.config ├── Web.Release.config ├── Web.config ├── favicon.ico ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff └── packages.config └── README.md /.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 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | # DNX 42 | project.lock.json 43 | artifacts/ 44 | 45 | *_i.c 46 | *_p.c 47 | *_i.h 48 | *.ilk 49 | *.meta 50 | *.obj 51 | *.pch 52 | *.pdb 53 | *.pgc 54 | *.pgd 55 | *.rsp 56 | *.sbr 57 | *.tlb 58 | *.tli 59 | *.tlh 60 | *.tmp 61 | *.tmp_proj 62 | *.log 63 | *.vspscc 64 | *.vssscc 65 | .builds 66 | *.pidb 67 | *.svclog 68 | *.scc 69 | 70 | # Chutzpah Test files 71 | _Chutzpah* 72 | 73 | # Visual C++ cache files 74 | ipch/ 75 | *.aps 76 | *.ncb 77 | *.opensdf 78 | *.sdf 79 | *.cachefile 80 | 81 | # Visual Studio profiler 82 | *.psess 83 | *.vsp 84 | *.vspx 85 | 86 | # TFS 2012 Local Workspace 87 | $tf/ 88 | 89 | # Guidance Automation Toolkit 90 | *.gpState 91 | 92 | # ReSharper is a .NET coding add-in 93 | _ReSharper*/ 94 | *.[Rr]e[Ss]harper 95 | *.DotSettings.user 96 | 97 | # JustCode is a .NET coding add-in 98 | .JustCode 99 | 100 | # TeamCity is a build add-in 101 | _TeamCity* 102 | 103 | # DotCover is a Code Coverage Tool 104 | *.dotCover 105 | 106 | # NCrunch 107 | _NCrunch_* 108 | .*crunch*.local.xml 109 | 110 | # MightyMoose 111 | *.mm.* 112 | AutoTest.Net/ 113 | 114 | # Web workbench (sass) 115 | .sass-cache/ 116 | 117 | # Installshield output folder 118 | [Ee]xpress/ 119 | 120 | # DocProject is a documentation generator add-in 121 | DocProject/buildhelp/ 122 | DocProject/Help/*.HxT 123 | DocProject/Help/*.HxC 124 | DocProject/Help/*.hhc 125 | DocProject/Help/*.hhk 126 | DocProject/Help/*.hhp 127 | DocProject/Help/Html2 128 | DocProject/Help/html 129 | 130 | # Click-Once directory 131 | publish/ 132 | 133 | # Publish Web Output 134 | *.[Pp]ublish.xml 135 | *.azurePubxml 136 | ## TODO: Comment the next line if you want to checkin your 137 | ## web deploy settings but do note that will include unencrypted 138 | ## passwords 139 | #*.pubxml 140 | 141 | *.publishproj 142 | 143 | # NuGet Packages 144 | *.nupkg 145 | # The packages folder can be ignored because of Package Restore 146 | **/packages/* 147 | # except build/, which is used as an MSBuild target. 148 | !**/packages/build/ 149 | # Uncomment if necessary however generally it will be regenerated when needed 150 | #!**/packages/repositories.config 151 | 152 | # Windows Azure Build Output 153 | csx/ 154 | *.build.csdef 155 | 156 | # Windows Store app package directory 157 | AppPackages/ 158 | 159 | # Visual Studio cache files 160 | # files ending in .cache can be ignored 161 | *.[Cc]ache 162 | # but keep track of directories ending in .cache 163 | !*.[Cc]ache/ 164 | 165 | # Others 166 | ClientBin/ 167 | [Ss]tyle[Cc]op.* 168 | ~$* 169 | *~ 170 | *.dbmdl 171 | *.dbproj.schemaview 172 | *.pfx 173 | *.publishsettings 174 | node_modules/ 175 | orleans.codegen.cs 176 | 177 | # RIA/Silverlight projects 178 | Generated_Code/ 179 | 180 | # Backup & report files from converting an old project file 181 | # to a newer Visual Studio version. Backup files are not needed, 182 | # because we have git ;-) 183 | _UpgradeReport_Files/ 184 | Backup*/ 185 | UpgradeLog*.XML 186 | UpgradeLog*.htm 187 | 188 | # SQL Server files 189 | *.mdf 190 | *.ldf 191 | 192 | # Business Intelligence projects 193 | *.rdl.data 194 | *.bim.layout 195 | *.bim_*.settings 196 | 197 | # Microsoft Fakes 198 | FakesAssemblies/ 199 | 200 | # Node.js Tools for Visual Studio 201 | .ntvs_analysis.dat 202 | 203 | # Visual Studio 6 build log 204 | *.plg 205 | 206 | # Visual Studio 6 workspace options file 207 | *.opt 208 | 209 | # LightSwitch generated files 210 | GeneratedArtifacts/ 211 | _Pvt_Extensions/ 212 | ModelManifest.xml 213 | -------------------------------------------------------------------------------- /ChatApplication.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatApplication", "ChatApplication\ChatApplication.csproj", "{CAF1C414-DDC8-404D-B9B6-EDBBAC8A3B4F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {CAF1C414-DDC8-404D-B9B6-EDBBAC8A3B4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {CAF1C414-DDC8-404D-B9B6-EDBBAC8A3B4F}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {CAF1C414-DDC8-404D-B9B6-EDBBAC8A3B4F}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {CAF1C414-DDC8-404D-B9B6-EDBBAC8A3B4F}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /ChatApplication/App_Start/BundleConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Optimization; 3 | 4 | namespace ChatApplication 5 | { 6 | public class BundleConfig 7 | { 8 | // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862 9 | public static void RegisterBundles(BundleCollection bundles) 10 | { 11 | bundles.Add(new ScriptBundle("~/bundles/jquery").Include( 12 | "~/Scripts/jquery-{version}.js")); 13 | 14 | bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( 15 | "~/Scripts/jquery.validate*")); 16 | 17 | // Use the development version of Modernizr to develop with and learn from. Then, when you're 18 | // ready for production, use the build tool at http://modernizr.com to pick only the tests you need. 19 | bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( 20 | "~/Scripts/modernizr-*")); 21 | 22 | bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( 23 | "~/Scripts/bootstrap.js", 24 | "~/Scripts/respond.js")); 25 | 26 | bundles.Add(new StyleBundle("~/Content/css").Include( 27 | "~/Content/bootstrap.css", 28 | "~/Content/site.css")); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ChatApplication/App_Start/FilterConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | 4 | namespace ChatApplication 5 | { 6 | public class FilterConfig 7 | { 8 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) 9 | { 10 | filters.Add(new HandleErrorAttribute()); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ChatApplication/App_Start/IdentityConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity; 4 | using System.Linq; 5 | using System.Security.Claims; 6 | using System.Threading.Tasks; 7 | using System.Web; 8 | using Microsoft.AspNet.Identity; 9 | using Microsoft.AspNet.Identity.EntityFramework; 10 | using Microsoft.AspNet.Identity.Owin; 11 | using Microsoft.Owin; 12 | using Microsoft.Owin.Security; 13 | using ChatApplication.Models; 14 | 15 | namespace ChatApplication 16 | { 17 | public class EmailService : IIdentityMessageService 18 | { 19 | public Task SendAsync(IdentityMessage message) 20 | { 21 | // Plug in your email service here to send an email. 22 | return Task.FromResult(0); 23 | } 24 | } 25 | 26 | public class SmsService : IIdentityMessageService 27 | { 28 | public Task SendAsync(IdentityMessage message) 29 | { 30 | // Plug in your SMS service here to send a text message. 31 | return Task.FromResult(0); 32 | } 33 | } 34 | 35 | // Configure the application user manager used in this application. UserManager is defined in ASP.NET Identity and is used by the application. 36 | public class ApplicationUserManager : UserManager 37 | { 38 | public ApplicationUserManager(IUserStore store) 39 | : base(store) 40 | { 41 | } 42 | 43 | public static ApplicationUserManager Create(IdentityFactoryOptions options, IOwinContext context) 44 | { 45 | var manager = new ApplicationUserManager(new UserStore(context.Get())); 46 | // Configure validation logic for usernames 47 | manager.UserValidator = new UserValidator(manager) 48 | { 49 | AllowOnlyAlphanumericUserNames = false, 50 | RequireUniqueEmail = true 51 | }; 52 | 53 | // Configure validation logic for passwords 54 | manager.PasswordValidator = new PasswordValidator 55 | { 56 | RequiredLength = 6, 57 | RequireNonLetterOrDigit = true, 58 | RequireDigit = true, 59 | RequireLowercase = true, 60 | RequireUppercase = true, 61 | }; 62 | 63 | // Configure user lockout defaults 64 | manager.UserLockoutEnabledByDefault = true; 65 | manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5); 66 | manager.MaxFailedAccessAttemptsBeforeLockout = 5; 67 | 68 | // Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user 69 | // You can write your own provider and plug it in here. 70 | manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider 71 | { 72 | MessageFormat = "Your security code is {0}" 73 | }); 74 | manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider 75 | { 76 | Subject = "Security Code", 77 | BodyFormat = "Your security code is {0}" 78 | }); 79 | manager.EmailService = new EmailService(); 80 | manager.SmsService = new SmsService(); 81 | var dataProtectionProvider = options.DataProtectionProvider; 82 | if (dataProtectionProvider != null) 83 | { 84 | manager.UserTokenProvider = 85 | new DataProtectorTokenProvider(dataProtectionProvider.Create("ASP.NET Identity")); 86 | } 87 | return manager; 88 | } 89 | } 90 | 91 | // Configure the application sign-in manager which is used in this application. 92 | public class ApplicationSignInManager : SignInManager 93 | { 94 | public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager) 95 | : base(userManager, authenticationManager) 96 | { 97 | } 98 | 99 | public override Task CreateUserIdentityAsync(ApplicationUser user) 100 | { 101 | return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager); 102 | } 103 | 104 | public static ApplicationSignInManager Create(IdentityFactoryOptions options, IOwinContext context) 105 | { 106 | return new ApplicationSignInManager(context.GetUserManager(), context.Authentication); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /ChatApplication/App_Start/RouteConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Routing; 7 | 8 | namespace ChatApplication 9 | { 10 | public class RouteConfig 11 | { 12 | public static void RegisterRoutes(RouteCollection routes) 13 | { 14 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 15 | 16 | routes.MapRoute( 17 | name: "Default", 18 | url: "{controller}/{action}/{id}", 19 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 20 | ); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ChatApplication/App_Start/Startup.Auth.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNet.Identity; 3 | using Microsoft.AspNet.Identity.Owin; 4 | using Microsoft.Owin; 5 | using Microsoft.Owin.Security.Cookies; 6 | using Microsoft.Owin.Security.Google; 7 | using Owin; 8 | using ChatApplication.Models; 9 | 10 | namespace ChatApplication 11 | { 12 | public partial class Startup 13 | { 14 | // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864 15 | public void ConfigureAuth(IAppBuilder app) 16 | { 17 | // Configure the db context, user manager and signin manager to use a single instance per request 18 | app.CreatePerOwinContext(ApplicationDbContext.Create); 19 | app.CreatePerOwinContext(ApplicationUserManager.Create); 20 | app.CreatePerOwinContext(ApplicationSignInManager.Create); 21 | 22 | // Enable the application to use a cookie to store information for the signed in user 23 | // and to use a cookie to temporarily store information about a user logging in with a third party login provider 24 | // Configure the sign in cookie 25 | app.UseCookieAuthentication(new CookieAuthenticationOptions 26 | { 27 | AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 28 | LoginPath = new PathString("/Account/Login"), 29 | Provider = new CookieAuthenticationProvider 30 | { 31 | // Enables the application to validate the security stamp when the user logs in. 32 | // This is a security feature which is used when you change a password or add an external login to your account. 33 | OnValidateIdentity = SecurityStampValidator.OnValidateIdentity( 34 | validateInterval: TimeSpan.FromMinutes(30), 35 | regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) 36 | } 37 | }); 38 | app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); 39 | 40 | // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process. 41 | app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5)); 42 | 43 | // Enables the application to remember the second login verification factor such as phone or email. 44 | // Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from. 45 | // This is similar to the RememberMe option when you log in. 46 | app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie); 47 | 48 | // Uncomment the following lines to enable logging in with third party login providers 49 | //app.UseMicrosoftAccountAuthentication( 50 | // clientId: "", 51 | // clientSecret: ""); 52 | 53 | //app.UseTwitterAuthentication( 54 | // consumerKey: "", 55 | // consumerSecret: ""); 56 | 57 | //app.UseFacebookAuthentication( 58 | // appId: "", 59 | // appSecret: ""); 60 | 61 | //app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions() 62 | //{ 63 | // ClientId = "", 64 | // ClientSecret = "" 65 | //}); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /ChatApplication/ChatApplication.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Debug 8 | AnyCPU 9 | 10 | 11 | 2.0 12 | {CAF1C414-DDC8-404D-B9B6-EDBBAC8A3B4F} 13 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 14 | Library 15 | Properties 16 | ChatApplication 17 | ChatApplication 18 | v4.5.2 19 | false 20 | true 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | true 31 | full 32 | false 33 | bin\ 34 | DEBUG;TRACE 35 | prompt 36 | 4 37 | 38 | 39 | pdbonly 40 | true 41 | bin\ 42 | TRACE 43 | prompt 44 | 4 45 | 46 | 47 | 48 | ..\packages\Microsoft.AspNet.SignalR.Core.2.2.0\lib\net45\Microsoft.AspNet.SignalR.Core.dll 49 | True 50 | 51 | 52 | ..\packages\Microsoft.AspNet.SignalR.SystemWeb.2.2.0\lib\net45\Microsoft.AspNet.SignalR.SystemWeb.dll 53 | True 54 | 55 | 56 | ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll 57 | True 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | True 80 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 81 | 82 | 83 | 84 | 85 | 86 | 87 | True 88 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll 89 | 90 | 91 | True 92 | ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll 93 | 94 | 95 | ..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll 96 | 97 | 98 | True 99 | ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll 100 | 101 | 102 | True 103 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll 104 | 105 | 106 | True 107 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll 108 | 109 | 110 | True 111 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll 112 | 113 | 114 | True 115 | ..\packages\WebGrease.1.5.2\lib\WebGrease.dll 116 | 117 | 118 | True 119 | ..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll 120 | 121 | 122 | 123 | 124 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll 125 | 126 | 127 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll 128 | 129 | 130 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll 131 | 132 | 133 | ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll 134 | 135 | 136 | ..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll 137 | 138 | 139 | ..\packages\Microsoft.AspNet.Identity.EntityFramework.2.2.1\lib\net45\Microsoft.AspNet.Identity.EntityFramework.dll 140 | 141 | 142 | ..\packages\Owin.1.0\lib\net40\Owin.dll 143 | 144 | 145 | ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll 146 | 147 | 148 | ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll 149 | 150 | 151 | ..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll 152 | 153 | 154 | ..\packages\Microsoft.Owin.Security.Facebook.3.0.1\lib\net45\Microsoft.Owin.Security.Facebook.dll 155 | 156 | 157 | ..\packages\Microsoft.Owin.Security.Cookies.3.0.1\lib\net45\Microsoft.Owin.Security.Cookies.dll 158 | 159 | 160 | ..\packages\Microsoft.Owin.Security.OAuth.3.0.1\lib\net45\Microsoft.Owin.Security.OAuth.dll 161 | 162 | 163 | ..\packages\Microsoft.Owin.Security.Google.3.0.1\lib\net45\Microsoft.Owin.Security.Google.dll 164 | 165 | 166 | ..\packages\Microsoft.Owin.Security.Twitter.3.0.1\lib\net45\Microsoft.Owin.Security.Twitter.dll 167 | 168 | 169 | ..\packages\Microsoft.Owin.Security.MicrosoftAccount.3.0.1\lib\net45\Microsoft.Owin.Security.MicrosoftAccount.dll 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | Global.asax 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | Web.config 219 | 220 | 221 | Web.config 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 10.0 264 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | True 277 | True 278 | 4168 279 | / 280 | http://localhost:4168/ 281 | False 282 | False 283 | 284 | 285 | False 286 | 287 | 288 | 289 | 290 | 291 | 292 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 293 | 294 | 295 | 296 | 297 | 303 | -------------------------------------------------------------------------------- /ChatApplication/Content/Site.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | padding-bottom: 20px; 4 | } 5 | 6 | /* Set padding to keep content from hitting the edges */ 7 | .body-content { 8 | padding-left: 15px; 9 | padding-right: 15px; 10 | } 11 | 12 | /* Override the default bootstrap behavior where horizontal description lists 13 | will truncate terms that are too long to fit in the left column 14 | */ 15 | .dl-horizontal dt { 16 | white-space: normal; 17 | } 18 | 19 | /* Set width on the form input elements since they're 100% wide by default */ 20 | input, 21 | select, 22 | textarea { 23 | max-width: 280px; 24 | } 25 | -------------------------------------------------------------------------------- /ChatApplication/Controllers/AccountController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Linq; 4 | using System.Security.Claims; 5 | using System.Threading.Tasks; 6 | using System.Web; 7 | using System.Web.Mvc; 8 | using Microsoft.AspNet.Identity; 9 | using Microsoft.AspNet.Identity.Owin; 10 | using Microsoft.Owin.Security; 11 | using ChatApplication.Models; 12 | 13 | namespace ChatApplication.Controllers 14 | { 15 | [Authorize] 16 | public class AccountController : Controller 17 | { 18 | private ApplicationSignInManager _signInManager; 19 | private ApplicationUserManager _userManager; 20 | 21 | public AccountController() 22 | { 23 | } 24 | 25 | public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager ) 26 | { 27 | UserManager = userManager; 28 | SignInManager = signInManager; 29 | } 30 | 31 | public ApplicationSignInManager SignInManager 32 | { 33 | get 34 | { 35 | return _signInManager ?? HttpContext.GetOwinContext().Get(); 36 | } 37 | private set 38 | { 39 | _signInManager = value; 40 | } 41 | } 42 | 43 | public ApplicationUserManager UserManager 44 | { 45 | get 46 | { 47 | return _userManager ?? HttpContext.GetOwinContext().GetUserManager(); 48 | } 49 | private set 50 | { 51 | _userManager = value; 52 | } 53 | } 54 | 55 | // 56 | // GET: /Account/Login 57 | [AllowAnonymous] 58 | public ActionResult Login(string returnUrl) 59 | { 60 | ViewBag.ReturnUrl = returnUrl; 61 | return View(); 62 | } 63 | 64 | // 65 | // POST: /Account/Login 66 | [HttpPost] 67 | [AllowAnonymous] 68 | [ValidateAntiForgeryToken] 69 | public async Task Login(LoginViewModel model, string returnUrl) 70 | { 71 | if (!ModelState.IsValid) 72 | { 73 | return View(model); 74 | } 75 | 76 | // This doesn't count login failures towards account lockout 77 | // To enable password failures to trigger account lockout, change to shouldLockout: true 78 | var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false); 79 | switch (result) 80 | { 81 | case SignInStatus.Success: 82 | return RedirectToLocal(returnUrl); 83 | case SignInStatus.LockedOut: 84 | return View("Lockout"); 85 | case SignInStatus.RequiresVerification: 86 | return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe }); 87 | case SignInStatus.Failure: 88 | default: 89 | ModelState.AddModelError("", "Invalid login attempt."); 90 | return View(model); 91 | } 92 | } 93 | 94 | // 95 | // GET: /Account/VerifyCode 96 | [AllowAnonymous] 97 | public async Task VerifyCode(string provider, string returnUrl, bool rememberMe) 98 | { 99 | // Require that the user has already logged in via username/password or external login 100 | if (!await SignInManager.HasBeenVerifiedAsync()) 101 | { 102 | return View("Error"); 103 | } 104 | return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe }); 105 | } 106 | 107 | // 108 | // POST: /Account/VerifyCode 109 | [HttpPost] 110 | [AllowAnonymous] 111 | [ValidateAntiForgeryToken] 112 | public async Task VerifyCode(VerifyCodeViewModel model) 113 | { 114 | if (!ModelState.IsValid) 115 | { 116 | return View(model); 117 | } 118 | 119 | // The following code protects for brute force attacks against the two factor codes. 120 | // If a user enters incorrect codes for a specified amount of time then the user account 121 | // will be locked out for a specified amount of time. 122 | // You can configure the account lockout settings in IdentityConfig 123 | var result = await SignInManager.TwoFactorSignInAsync(model.Provider, model.Code, isPersistent: model.RememberMe, rememberBrowser: model.RememberBrowser); 124 | switch (result) 125 | { 126 | case SignInStatus.Success: 127 | return RedirectToLocal(model.ReturnUrl); 128 | case SignInStatus.LockedOut: 129 | return View("Lockout"); 130 | case SignInStatus.Failure: 131 | default: 132 | ModelState.AddModelError("", "Invalid code."); 133 | return View(model); 134 | } 135 | } 136 | 137 | // 138 | // GET: /Account/Register 139 | [AllowAnonymous] 140 | public ActionResult Register() 141 | { 142 | return View(); 143 | } 144 | 145 | // 146 | // POST: /Account/Register 147 | [HttpPost] 148 | [AllowAnonymous] 149 | [ValidateAntiForgeryToken] 150 | public async Task Register(RegisterViewModel model) 151 | { 152 | if (ModelState.IsValid) 153 | { 154 | var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; 155 | var result = await UserManager.CreateAsync(user, model.Password); 156 | if (result.Succeeded) 157 | { 158 | await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false); 159 | 160 | // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771 161 | // Send an email with this link 162 | // string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id); 163 | // var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme); 164 | // await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here"); 165 | 166 | return RedirectToAction("Index", "Home"); 167 | } 168 | AddErrors(result); 169 | } 170 | 171 | // If we got this far, something failed, redisplay form 172 | return View(model); 173 | } 174 | 175 | // 176 | // GET: /Account/ConfirmEmail 177 | [AllowAnonymous] 178 | public async Task ConfirmEmail(string userId, string code) 179 | { 180 | if (userId == null || code == null) 181 | { 182 | return View("Error"); 183 | } 184 | var result = await UserManager.ConfirmEmailAsync(userId, code); 185 | return View(result.Succeeded ? "ConfirmEmail" : "Error"); 186 | } 187 | 188 | // 189 | // GET: /Account/ForgotPassword 190 | [AllowAnonymous] 191 | public ActionResult ForgotPassword() 192 | { 193 | return View(); 194 | } 195 | 196 | // 197 | // POST: /Account/ForgotPassword 198 | [HttpPost] 199 | [AllowAnonymous] 200 | [ValidateAntiForgeryToken] 201 | public async Task ForgotPassword(ForgotPasswordViewModel model) 202 | { 203 | if (ModelState.IsValid) 204 | { 205 | var user = await UserManager.FindByNameAsync(model.Email); 206 | if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id))) 207 | { 208 | // Don't reveal that the user does not exist or is not confirmed 209 | return View("ForgotPasswordConfirmation"); 210 | } 211 | 212 | // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771 213 | // Send an email with this link 214 | // string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id); 215 | // var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme); 216 | // await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking here"); 217 | // return RedirectToAction("ForgotPasswordConfirmation", "Account"); 218 | } 219 | 220 | // If we got this far, something failed, redisplay form 221 | return View(model); 222 | } 223 | 224 | // 225 | // GET: /Account/ForgotPasswordConfirmation 226 | [AllowAnonymous] 227 | public ActionResult ForgotPasswordConfirmation() 228 | { 229 | return View(); 230 | } 231 | 232 | // 233 | // GET: /Account/ResetPassword 234 | [AllowAnonymous] 235 | public ActionResult ResetPassword(string code) 236 | { 237 | return code == null ? View("Error") : View(); 238 | } 239 | 240 | // 241 | // POST: /Account/ResetPassword 242 | [HttpPost] 243 | [AllowAnonymous] 244 | [ValidateAntiForgeryToken] 245 | public async Task ResetPassword(ResetPasswordViewModel model) 246 | { 247 | if (!ModelState.IsValid) 248 | { 249 | return View(model); 250 | } 251 | var user = await UserManager.FindByNameAsync(model.Email); 252 | if (user == null) 253 | { 254 | // Don't reveal that the user does not exist 255 | return RedirectToAction("ResetPasswordConfirmation", "Account"); 256 | } 257 | var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password); 258 | if (result.Succeeded) 259 | { 260 | return RedirectToAction("ResetPasswordConfirmation", "Account"); 261 | } 262 | AddErrors(result); 263 | return View(); 264 | } 265 | 266 | // 267 | // GET: /Account/ResetPasswordConfirmation 268 | [AllowAnonymous] 269 | public ActionResult ResetPasswordConfirmation() 270 | { 271 | return View(); 272 | } 273 | 274 | // 275 | // POST: /Account/ExternalLogin 276 | [HttpPost] 277 | [AllowAnonymous] 278 | [ValidateAntiForgeryToken] 279 | public ActionResult ExternalLogin(string provider, string returnUrl) 280 | { 281 | // Request a redirect to the external login provider 282 | return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl })); 283 | } 284 | 285 | // 286 | // GET: /Account/SendCode 287 | [AllowAnonymous] 288 | public async Task SendCode(string returnUrl, bool rememberMe) 289 | { 290 | var userId = await SignInManager.GetVerifiedUserIdAsync(); 291 | if (userId == null) 292 | { 293 | return View("Error"); 294 | } 295 | var userFactors = await UserManager.GetValidTwoFactorProvidersAsync(userId); 296 | var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList(); 297 | return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe }); 298 | } 299 | 300 | // 301 | // POST: /Account/SendCode 302 | [HttpPost] 303 | [AllowAnonymous] 304 | [ValidateAntiForgeryToken] 305 | public async Task SendCode(SendCodeViewModel model) 306 | { 307 | if (!ModelState.IsValid) 308 | { 309 | return View(); 310 | } 311 | 312 | // Generate the token and send it 313 | if (!await SignInManager.SendTwoFactorCodeAsync(model.SelectedProvider)) 314 | { 315 | return View("Error"); 316 | } 317 | return RedirectToAction("VerifyCode", new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe }); 318 | } 319 | 320 | // 321 | // GET: /Account/ExternalLoginCallback 322 | [AllowAnonymous] 323 | public async Task ExternalLoginCallback(string returnUrl) 324 | { 325 | var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(); 326 | if (loginInfo == null) 327 | { 328 | return RedirectToAction("Login"); 329 | } 330 | 331 | // Sign in the user with this external login provider if the user already has a login 332 | var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false); 333 | switch (result) 334 | { 335 | case SignInStatus.Success: 336 | return RedirectToLocal(returnUrl); 337 | case SignInStatus.LockedOut: 338 | return View("Lockout"); 339 | case SignInStatus.RequiresVerification: 340 | return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false }); 341 | case SignInStatus.Failure: 342 | default: 343 | // If the user does not have an account, then prompt the user to create an account 344 | ViewBag.ReturnUrl = returnUrl; 345 | ViewBag.LoginProvider = loginInfo.Login.LoginProvider; 346 | return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email }); 347 | } 348 | } 349 | 350 | // 351 | // POST: /Account/ExternalLoginConfirmation 352 | [HttpPost] 353 | [AllowAnonymous] 354 | [ValidateAntiForgeryToken] 355 | public async Task ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl) 356 | { 357 | if (User.Identity.IsAuthenticated) 358 | { 359 | return RedirectToAction("Index", "Manage"); 360 | } 361 | 362 | if (ModelState.IsValid) 363 | { 364 | // Get the information about the user from the external login provider 365 | var info = await AuthenticationManager.GetExternalLoginInfoAsync(); 366 | if (info == null) 367 | { 368 | return View("ExternalLoginFailure"); 369 | } 370 | var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; 371 | var result = await UserManager.CreateAsync(user); 372 | if (result.Succeeded) 373 | { 374 | result = await UserManager.AddLoginAsync(user.Id, info.Login); 375 | if (result.Succeeded) 376 | { 377 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); 378 | return RedirectToLocal(returnUrl); 379 | } 380 | } 381 | AddErrors(result); 382 | } 383 | 384 | ViewBag.ReturnUrl = returnUrl; 385 | return View(model); 386 | } 387 | 388 | // 389 | // POST: /Account/LogOff 390 | [HttpPost] 391 | [ValidateAntiForgeryToken] 392 | public ActionResult LogOff() 393 | { 394 | AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie); 395 | return RedirectToAction("Index", "Home"); 396 | } 397 | 398 | // 399 | // GET: /Account/ExternalLoginFailure 400 | [AllowAnonymous] 401 | public ActionResult ExternalLoginFailure() 402 | { 403 | return View(); 404 | } 405 | 406 | protected override void Dispose(bool disposing) 407 | { 408 | if (disposing) 409 | { 410 | if (_userManager != null) 411 | { 412 | _userManager.Dispose(); 413 | _userManager = null; 414 | } 415 | 416 | if (_signInManager != null) 417 | { 418 | _signInManager.Dispose(); 419 | _signInManager = null; 420 | } 421 | } 422 | 423 | base.Dispose(disposing); 424 | } 425 | 426 | #region Helpers 427 | // Used for XSRF protection when adding external logins 428 | private const string XsrfKey = "XsrfId"; 429 | 430 | private IAuthenticationManager AuthenticationManager 431 | { 432 | get 433 | { 434 | return HttpContext.GetOwinContext().Authentication; 435 | } 436 | } 437 | 438 | private void AddErrors(IdentityResult result) 439 | { 440 | foreach (var error in result.Errors) 441 | { 442 | ModelState.AddModelError("", error); 443 | } 444 | } 445 | 446 | private ActionResult RedirectToLocal(string returnUrl) 447 | { 448 | if (Url.IsLocalUrl(returnUrl)) 449 | { 450 | return Redirect(returnUrl); 451 | } 452 | return RedirectToAction("Index", "Home"); 453 | } 454 | 455 | internal class ChallengeResult : HttpUnauthorizedResult 456 | { 457 | public ChallengeResult(string provider, string redirectUri) 458 | : this(provider, redirectUri, null) 459 | { 460 | } 461 | 462 | public ChallengeResult(string provider, string redirectUri, string userId) 463 | { 464 | LoginProvider = provider; 465 | RedirectUri = redirectUri; 466 | UserId = userId; 467 | } 468 | 469 | public string LoginProvider { get; set; } 470 | public string RedirectUri { get; set; } 471 | public string UserId { get; set; } 472 | 473 | public override void ExecuteResult(ControllerContext context) 474 | { 475 | var properties = new AuthenticationProperties { RedirectUri = RedirectUri }; 476 | if (UserId != null) 477 | { 478 | properties.Dictionary[XsrfKey] = UserId; 479 | } 480 | context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider); 481 | } 482 | } 483 | #endregion 484 | } 485 | } -------------------------------------------------------------------------------- /ChatApplication/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | 7 | namespace ChatApplication.Controllers 8 | { 9 | public class HomeController : Controller 10 | { 11 | public ActionResult Index() 12 | { 13 | return View(); 14 | } 15 | 16 | public ActionResult About() 17 | { 18 | ViewBag.Message = "Your application description page."; 19 | 20 | return View(); 21 | } 22 | 23 | public ActionResult Contact() 24 | { 25 | ViewBag.Message = "Your contact page."; 26 | 27 | return View(); 28 | } 29 | 30 | public ActionResult Chat() 31 | { 32 | return View(); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /ChatApplication/Controllers/ManageController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using Microsoft.AspNet.Identity; 7 | using Microsoft.AspNet.Identity.Owin; 8 | using Microsoft.Owin.Security; 9 | using ChatApplication.Models; 10 | 11 | namespace ChatApplication.Controllers 12 | { 13 | [Authorize] 14 | public class ManageController : Controller 15 | { 16 | private ApplicationSignInManager _signInManager; 17 | private ApplicationUserManager _userManager; 18 | 19 | public ManageController() 20 | { 21 | } 22 | 23 | public ManageController(ApplicationUserManager userManager, ApplicationSignInManager signInManager) 24 | { 25 | UserManager = userManager; 26 | SignInManager = signInManager; 27 | } 28 | 29 | public ApplicationSignInManager SignInManager 30 | { 31 | get 32 | { 33 | return _signInManager ?? HttpContext.GetOwinContext().Get(); 34 | } 35 | private set 36 | { 37 | _signInManager = value; 38 | } 39 | } 40 | 41 | public ApplicationUserManager UserManager 42 | { 43 | get 44 | { 45 | return _userManager ?? HttpContext.GetOwinContext().GetUserManager(); 46 | } 47 | private set 48 | { 49 | _userManager = value; 50 | } 51 | } 52 | 53 | // 54 | // GET: /Manage/Index 55 | public async Task Index(ManageMessageId? message) 56 | { 57 | ViewBag.StatusMessage = 58 | message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." 59 | : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." 60 | : message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set." 61 | : message == ManageMessageId.Error ? "An error has occurred." 62 | : message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added." 63 | : message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed." 64 | : ""; 65 | 66 | var userId = User.Identity.GetUserId(); 67 | var model = new IndexViewModel 68 | { 69 | HasPassword = HasPassword(), 70 | PhoneNumber = await UserManager.GetPhoneNumberAsync(userId), 71 | TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId), 72 | Logins = await UserManager.GetLoginsAsync(userId), 73 | BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId) 74 | }; 75 | return View(model); 76 | } 77 | 78 | // 79 | // POST: /Manage/RemoveLogin 80 | [HttpPost] 81 | [ValidateAntiForgeryToken] 82 | public async Task RemoveLogin(string loginProvider, string providerKey) 83 | { 84 | ManageMessageId? message; 85 | var result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey)); 86 | if (result.Succeeded) 87 | { 88 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 89 | if (user != null) 90 | { 91 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); 92 | } 93 | message = ManageMessageId.RemoveLoginSuccess; 94 | } 95 | else 96 | { 97 | message = ManageMessageId.Error; 98 | } 99 | return RedirectToAction("ManageLogins", new { Message = message }); 100 | } 101 | 102 | // 103 | // GET: /Manage/AddPhoneNumber 104 | public ActionResult AddPhoneNumber() 105 | { 106 | return View(); 107 | } 108 | 109 | // 110 | // POST: /Manage/AddPhoneNumber 111 | [HttpPost] 112 | [ValidateAntiForgeryToken] 113 | public async Task AddPhoneNumber(AddPhoneNumberViewModel model) 114 | { 115 | if (!ModelState.IsValid) 116 | { 117 | return View(model); 118 | } 119 | // Generate the token and send it 120 | var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), model.Number); 121 | if (UserManager.SmsService != null) 122 | { 123 | var message = new IdentityMessage 124 | { 125 | Destination = model.Number, 126 | Body = "Your security code is: " + code 127 | }; 128 | await UserManager.SmsService.SendAsync(message); 129 | } 130 | return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number }); 131 | } 132 | 133 | // 134 | // POST: /Manage/EnableTwoFactorAuthentication 135 | [HttpPost] 136 | [ValidateAntiForgeryToken] 137 | public async Task EnableTwoFactorAuthentication() 138 | { 139 | await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true); 140 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 141 | if (user != null) 142 | { 143 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); 144 | } 145 | return RedirectToAction("Index", "Manage"); 146 | } 147 | 148 | // 149 | // POST: /Manage/DisableTwoFactorAuthentication 150 | [HttpPost] 151 | [ValidateAntiForgeryToken] 152 | public async Task DisableTwoFactorAuthentication() 153 | { 154 | await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), false); 155 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 156 | if (user != null) 157 | { 158 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); 159 | } 160 | return RedirectToAction("Index", "Manage"); 161 | } 162 | 163 | // 164 | // GET: /Manage/VerifyPhoneNumber 165 | public async Task VerifyPhoneNumber(string phoneNumber) 166 | { 167 | var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), phoneNumber); 168 | // Send an SMS through the SMS provider to verify the phone number 169 | return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber }); 170 | } 171 | 172 | // 173 | // POST: /Manage/VerifyPhoneNumber 174 | [HttpPost] 175 | [ValidateAntiForgeryToken] 176 | public async Task VerifyPhoneNumber(VerifyPhoneNumberViewModel model) 177 | { 178 | if (!ModelState.IsValid) 179 | { 180 | return View(model); 181 | } 182 | var result = await UserManager.ChangePhoneNumberAsync(User.Identity.GetUserId(), model.PhoneNumber, model.Code); 183 | if (result.Succeeded) 184 | { 185 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 186 | if (user != null) 187 | { 188 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); 189 | } 190 | return RedirectToAction("Index", new { Message = ManageMessageId.AddPhoneSuccess }); 191 | } 192 | // If we got this far, something failed, redisplay form 193 | ModelState.AddModelError("", "Failed to verify phone"); 194 | return View(model); 195 | } 196 | 197 | // 198 | // GET: /Manage/RemovePhoneNumber 199 | public async Task RemovePhoneNumber() 200 | { 201 | var result = await UserManager.SetPhoneNumberAsync(User.Identity.GetUserId(), null); 202 | if (!result.Succeeded) 203 | { 204 | return RedirectToAction("Index", new { Message = ManageMessageId.Error }); 205 | } 206 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 207 | if (user != null) 208 | { 209 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); 210 | } 211 | return RedirectToAction("Index", new { Message = ManageMessageId.RemovePhoneSuccess }); 212 | } 213 | 214 | // 215 | // GET: /Manage/ChangePassword 216 | public ActionResult ChangePassword() 217 | { 218 | return View(); 219 | } 220 | 221 | // 222 | // POST: /Manage/ChangePassword 223 | [HttpPost] 224 | [ValidateAntiForgeryToken] 225 | public async Task ChangePassword(ChangePasswordViewModel model) 226 | { 227 | if (!ModelState.IsValid) 228 | { 229 | return View(model); 230 | } 231 | var result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword); 232 | if (result.Succeeded) 233 | { 234 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 235 | if (user != null) 236 | { 237 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); 238 | } 239 | return RedirectToAction("Index", new { Message = ManageMessageId.ChangePasswordSuccess }); 240 | } 241 | AddErrors(result); 242 | return View(model); 243 | } 244 | 245 | // 246 | // GET: /Manage/SetPassword 247 | public ActionResult SetPassword() 248 | { 249 | return View(); 250 | } 251 | 252 | // 253 | // POST: /Manage/SetPassword 254 | [HttpPost] 255 | [ValidateAntiForgeryToken] 256 | public async Task SetPassword(SetPasswordViewModel model) 257 | { 258 | if (ModelState.IsValid) 259 | { 260 | var result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword); 261 | if (result.Succeeded) 262 | { 263 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 264 | if (user != null) 265 | { 266 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); 267 | } 268 | return RedirectToAction("Index", new { Message = ManageMessageId.SetPasswordSuccess }); 269 | } 270 | AddErrors(result); 271 | } 272 | 273 | // If we got this far, something failed, redisplay form 274 | return View(model); 275 | } 276 | 277 | // 278 | // GET: /Manage/ManageLogins 279 | public async Task ManageLogins(ManageMessageId? message) 280 | { 281 | ViewBag.StatusMessage = 282 | message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." 283 | : message == ManageMessageId.Error ? "An error has occurred." 284 | : ""; 285 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 286 | if (user == null) 287 | { 288 | return View("Error"); 289 | } 290 | var userLogins = await UserManager.GetLoginsAsync(User.Identity.GetUserId()); 291 | var otherLogins = AuthenticationManager.GetExternalAuthenticationTypes().Where(auth => userLogins.All(ul => auth.AuthenticationType != ul.LoginProvider)).ToList(); 292 | ViewBag.ShowRemoveButton = user.PasswordHash != null || userLogins.Count > 1; 293 | return View(new ManageLoginsViewModel 294 | { 295 | CurrentLogins = userLogins, 296 | OtherLogins = otherLogins 297 | }); 298 | } 299 | 300 | // 301 | // POST: /Manage/LinkLogin 302 | [HttpPost] 303 | [ValidateAntiForgeryToken] 304 | public ActionResult LinkLogin(string provider) 305 | { 306 | // Request a redirect to the external login provider to link a login for the current user 307 | return new AccountController.ChallengeResult(provider, Url.Action("LinkLoginCallback", "Manage"), User.Identity.GetUserId()); 308 | } 309 | 310 | // 311 | // GET: /Manage/LinkLoginCallback 312 | public async Task LinkLoginCallback() 313 | { 314 | var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId()); 315 | if (loginInfo == null) 316 | { 317 | return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error }); 318 | } 319 | var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login); 320 | return result.Succeeded ? RedirectToAction("ManageLogins") : RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error }); 321 | } 322 | 323 | protected override void Dispose(bool disposing) 324 | { 325 | if (disposing && _userManager != null) 326 | { 327 | _userManager.Dispose(); 328 | _userManager = null; 329 | } 330 | 331 | base.Dispose(disposing); 332 | } 333 | 334 | #region Helpers 335 | // Used for XSRF protection when adding external logins 336 | private const string XsrfKey = "XsrfId"; 337 | 338 | private IAuthenticationManager AuthenticationManager 339 | { 340 | get 341 | { 342 | return HttpContext.GetOwinContext().Authentication; 343 | } 344 | } 345 | 346 | private void AddErrors(IdentityResult result) 347 | { 348 | foreach (var error in result.Errors) 349 | { 350 | ModelState.AddModelError("", error); 351 | } 352 | } 353 | 354 | private bool HasPassword() 355 | { 356 | var user = UserManager.FindById(User.Identity.GetUserId()); 357 | if (user != null) 358 | { 359 | return user.PasswordHash != null; 360 | } 361 | return false; 362 | } 363 | 364 | private bool HasPhoneNumber() 365 | { 366 | var user = UserManager.FindById(User.Identity.GetUserId()); 367 | if (user != null) 368 | { 369 | return user.PhoneNumber != null; 370 | } 371 | return false; 372 | } 373 | 374 | public enum ManageMessageId 375 | { 376 | AddPhoneSuccess, 377 | ChangePasswordSuccess, 378 | SetTwoFactorSuccess, 379 | SetPasswordSuccess, 380 | RemoveLoginSuccess, 381 | RemovePhoneSuccess, 382 | Error 383 | } 384 | 385 | #endregion 386 | } 387 | } -------------------------------------------------------------------------------- /ChatApplication/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="ChatApplication.MvcApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /ChatApplication/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Optimization; 7 | using System.Web.Routing; 8 | 9 | namespace ChatApplication 10 | { 11 | public class MvcApplication : System.Web.HttpApplication 12 | { 13 | protected void Application_Start() 14 | { 15 | AreaRegistration.RegisterAllAreas(); 16 | FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 17 | RouteConfig.RegisterRoutes(RouteTable.Routes); 18 | BundleConfig.RegisterBundles(BundleTable.Bundles); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ChatApplication/Hubs/ChatHub.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.SignalR; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using System.Web; 7 | 8 | namespace ChatApplication.Hubs 9 | { 10 | public class ChatHub : Hub 11 | { 12 | public void SendMessage(string name, string message, string roomName) 13 | { 14 | Clients.Group(roomName).GetMessage(name, message); 15 | } 16 | 17 | public Task JoinRoom(string roomName) 18 | { 19 | return Groups.Add(Context.ConnectionId, roomName); 20 | } 21 | 22 | public Task LeaveRooom(string roomName) 23 | { 24 | return Groups.Remove(Context.ConnectionId, roomName); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /ChatApplication/Models/AccountViewModels.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace ChatApplication.Models 5 | { 6 | public class ExternalLoginConfirmationViewModel 7 | { 8 | [Required] 9 | [Display(Name = "Email")] 10 | public string Email { get; set; } 11 | } 12 | 13 | public class ExternalLoginListViewModel 14 | { 15 | public string ReturnUrl { get; set; } 16 | } 17 | 18 | public class SendCodeViewModel 19 | { 20 | public string SelectedProvider { get; set; } 21 | public ICollection Providers { get; set; } 22 | public string ReturnUrl { get; set; } 23 | public bool RememberMe { get; set; } 24 | } 25 | 26 | public class VerifyCodeViewModel 27 | { 28 | [Required] 29 | public string Provider { get; set; } 30 | 31 | [Required] 32 | [Display(Name = "Code")] 33 | public string Code { get; set; } 34 | public string ReturnUrl { get; set; } 35 | 36 | [Display(Name = "Remember this browser?")] 37 | public bool RememberBrowser { get; set; } 38 | 39 | public bool RememberMe { get; set; } 40 | } 41 | 42 | public class ForgotViewModel 43 | { 44 | [Required] 45 | [Display(Name = "Email")] 46 | public string Email { get; set; } 47 | } 48 | 49 | public class LoginViewModel 50 | { 51 | [Required] 52 | [Display(Name = "Email")] 53 | [EmailAddress] 54 | public string Email { get; set; } 55 | 56 | [Required] 57 | [DataType(DataType.Password)] 58 | [Display(Name = "Password")] 59 | public string Password { get; set; } 60 | 61 | [Display(Name = "Remember me?")] 62 | public bool RememberMe { get; set; } 63 | } 64 | 65 | public class RegisterViewModel 66 | { 67 | [Required] 68 | [EmailAddress] 69 | [Display(Name = "Email")] 70 | public string Email { get; set; } 71 | 72 | [Required] 73 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 74 | [DataType(DataType.Password)] 75 | [Display(Name = "Password")] 76 | public string Password { get; set; } 77 | 78 | [DataType(DataType.Password)] 79 | [Display(Name = "Confirm password")] 80 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 81 | public string ConfirmPassword { get; set; } 82 | } 83 | 84 | public class ResetPasswordViewModel 85 | { 86 | [Required] 87 | [EmailAddress] 88 | [Display(Name = "Email")] 89 | public string Email { get; set; } 90 | 91 | [Required] 92 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 93 | [DataType(DataType.Password)] 94 | [Display(Name = "Password")] 95 | public string Password { get; set; } 96 | 97 | [DataType(DataType.Password)] 98 | [Display(Name = "Confirm password")] 99 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 100 | public string ConfirmPassword { get; set; } 101 | 102 | public string Code { get; set; } 103 | } 104 | 105 | public class ForgotPasswordViewModel 106 | { 107 | [Required] 108 | [EmailAddress] 109 | [Display(Name = "Email")] 110 | public string Email { get; set; } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /ChatApplication/Models/IdentityModels.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Entity; 2 | using System.Security.Claims; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNet.Identity; 5 | using Microsoft.AspNet.Identity.EntityFramework; 6 | 7 | namespace ChatApplication.Models 8 | { 9 | // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more. 10 | public class ApplicationUser : IdentityUser 11 | { 12 | public async Task GenerateUserIdentityAsync(UserManager manager) 13 | { 14 | // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType 15 | var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); 16 | // Add custom user claims here 17 | return userIdentity; 18 | } 19 | } 20 | 21 | public class ApplicationDbContext : IdentityDbContext 22 | { 23 | public ApplicationDbContext() 24 | : base("DefaultConnection", throwIfV1Schema: false) 25 | { 26 | } 27 | 28 | public static ApplicationDbContext Create() 29 | { 30 | return new ApplicationDbContext(); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /ChatApplication/Models/ManageViewModels.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | using Microsoft.AspNet.Identity; 4 | using Microsoft.Owin.Security; 5 | 6 | namespace ChatApplication.Models 7 | { 8 | public class IndexViewModel 9 | { 10 | public bool HasPassword { get; set; } 11 | public IList Logins { get; set; } 12 | public string PhoneNumber { get; set; } 13 | public bool TwoFactor { get; set; } 14 | public bool BrowserRemembered { get; set; } 15 | } 16 | 17 | public class ManageLoginsViewModel 18 | { 19 | public IList CurrentLogins { get; set; } 20 | public IList OtherLogins { get; set; } 21 | } 22 | 23 | public class FactorViewModel 24 | { 25 | public string Purpose { get; set; } 26 | } 27 | 28 | public class SetPasswordViewModel 29 | { 30 | [Required] 31 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 32 | [DataType(DataType.Password)] 33 | [Display(Name = "New password")] 34 | public string NewPassword { get; set; } 35 | 36 | [DataType(DataType.Password)] 37 | [Display(Name = "Confirm new password")] 38 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] 39 | public string ConfirmPassword { get; set; } 40 | } 41 | 42 | public class ChangePasswordViewModel 43 | { 44 | [Required] 45 | [DataType(DataType.Password)] 46 | [Display(Name = "Current password")] 47 | public string OldPassword { get; set; } 48 | 49 | [Required] 50 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 51 | [DataType(DataType.Password)] 52 | [Display(Name = "New password")] 53 | public string NewPassword { get; set; } 54 | 55 | [DataType(DataType.Password)] 56 | [Display(Name = "Confirm new password")] 57 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] 58 | public string ConfirmPassword { get; set; } 59 | } 60 | 61 | public class AddPhoneNumberViewModel 62 | { 63 | [Required] 64 | [Phone] 65 | [Display(Name = "Phone Number")] 66 | public string Number { get; set; } 67 | } 68 | 69 | public class VerifyPhoneNumberViewModel 70 | { 71 | [Required] 72 | [Display(Name = "Code")] 73 | public string Code { get; set; } 74 | 75 | [Required] 76 | [Phone] 77 | [Display(Name = "Phone Number")] 78 | public string PhoneNumber { get; set; } 79 | } 80 | 81 | public class ConfigureTwoFactorViewModel 82 | { 83 | public string SelectedProvider { get; set; } 84 | public ICollection Providers { get; set; } 85 | } 86 | } -------------------------------------------------------------------------------- /ChatApplication/Project_Readme.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Your ASP.NET application 6 | 95 | 96 | 97 | 98 | 102 | 103 |
104 |
105 |

This application consists of:

106 |
    107 |
  • Sample pages showing basic nav between Home, About, and Contact
  • 108 |
  • Theming using Bootstrap
  • 109 |
  • Authentication, if selected, shows how to register and sign in
  • 110 |
  • ASP.NET features managed using NuGet
  • 111 |
112 |
113 | 114 | 131 | 132 |
133 |

Deploy

134 | 139 |
140 | 141 |
142 |

Get help

143 | 147 |
148 |
149 | 150 | 151 | -------------------------------------------------------------------------------- /ChatApplication/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ChatApplication")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ChatApplication")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("9aa957d9-f165-4ce1-a60e-97244ba99e9b")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /ChatApplication/Properties/PublishProfiles/XamarinChat - Web Deploy.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | MSDeploy 9 | False 10 | AzureWebSite 11 | Release 12 | Any CPU 13 | http://xamarinchat.azurewebsites.net 14 | True 15 | False 16 | xamarinchat.scm.azurewebsites.net:443 17 | XamarinChat 18 | 19 | True 20 | WMSVC 21 | True 22 | $XamarinChat 23 | <_SavePWD>True 24 | <_DestinationType>AzureWebSite 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /ChatApplication/Scripts/_references.js: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | /// 7 | /// 8 | /// 9 | /// 10 | -------------------------------------------------------------------------------- /ChatApplication/Scripts/jquery.validate.min.js: -------------------------------------------------------------------------------- 1 | /* NUGET: BEGIN LICENSE TEXT 2 | * 3 | * Microsoft grants you the right to use these script files for the sole 4 | * purpose of either: (i) interacting through your browser with the Microsoft 5 | * website or online service, subject to the applicable licensing or use 6 | * terms; or (ii) using the files as included with a Microsoft product subject 7 | * to that product's license terms. Microsoft reserves all other rights to the 8 | * files not expressly granted by Microsoft, whether by implication, estoppel 9 | * or otherwise. Insofar as a script file is dual licensed under GPL, 10 | * Microsoft neither took the code under GPL nor distributes it thereunder but 11 | * under the terms set out in this paragraph. All notices and licenses 12 | * below are for informational purposes only. 13 | * 14 | * NUGET: END LICENSE TEXT */ 15 | /*! jQuery Validation Plugin - v1.11.1 - 3/22/2013\n* https://github.com/jzaefferer/jquery-validation 16 | * Copyright (c) 2013 Jörn Zaefferer; Licensed MIT */(function(t){t.extend(t.fn,{validate:function(e){if(!this.length)return e&&e.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."),void 0;var i=t.data(this[0],"validator");return i?i:(this.attr("novalidate","novalidate"),i=new t.validator(e,this[0]),t.data(this[0],"validator",i),i.settings.onsubmit&&(this.validateDelegate(":submit","click",function(e){i.settings.submitHandler&&(i.submitButton=e.target),t(e.target).hasClass("cancel")&&(i.cancelSubmit=!0),void 0!==t(e.target).attr("formnovalidate")&&(i.cancelSubmit=!0)}),this.submit(function(e){function s(){var s;return i.settings.submitHandler?(i.submitButton&&(s=t("").attr("name",i.submitButton.name).val(t(i.submitButton).val()).appendTo(i.currentForm)),i.settings.submitHandler.call(i,i.currentForm,e),i.submitButton&&s.remove(),!1):!0}return i.settings.debug&&e.preventDefault(),i.cancelSubmit?(i.cancelSubmit=!1,s()):i.form()?i.pendingRequest?(i.formSubmitted=!0,!1):s():(i.focusInvalid(),!1)})),i)},valid:function(){if(t(this[0]).is("form"))return this.validate().form();var e=!0,i=t(this[0].form).validate();return this.each(function(){e=e&&i.element(this)}),e},removeAttrs:function(e){var i={},s=this;return t.each(e.split(/\s/),function(t,e){i[e]=s.attr(e),s.removeAttr(e)}),i},rules:function(e,i){var s=this[0];if(e){var r=t.data(s.form,"validator").settings,n=r.rules,a=t.validator.staticRules(s);switch(e){case"add":t.extend(a,t.validator.normalizeRule(i)),delete a.messages,n[s.name]=a,i.messages&&(r.messages[s.name]=t.extend(r.messages[s.name],i.messages));break;case"remove":if(!i)return delete n[s.name],a;var u={};return t.each(i.split(/\s/),function(t,e){u[e]=a[e],delete a[e]}),u}}var o=t.validator.normalizeRules(t.extend({},t.validator.classRules(s),t.validator.attributeRules(s),t.validator.dataRules(s),t.validator.staticRules(s)),s);if(o.required){var l=o.required;delete o.required,o=t.extend({required:l},o)}return o}}),t.extend(t.expr[":"],{blank:function(e){return!t.trim(""+t(e).val())},filled:function(e){return!!t.trim(""+t(e).val())},unchecked:function(e){return!t(e).prop("checked")}}),t.validator=function(e,i){this.settings=t.extend(!0,{},t.validator.defaults,e),this.currentForm=i,this.init()},t.validator.format=function(e,i){return 1===arguments.length?function(){var i=t.makeArray(arguments);return i.unshift(e),t.validator.format.apply(this,i)}:(arguments.length>2&&i.constructor!==Array&&(i=t.makeArray(arguments).slice(1)),i.constructor!==Array&&(i=[i]),t.each(i,function(t,i){e=e.replace(RegExp("\\{"+t+"\\}","g"),function(){return i})}),e)},t.extend(t.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",validClass:"valid",errorElement:"label",focusInvalid:!0,errorContainer:t([]),errorLabelContainer:t([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(t){this.lastActive=t,this.settings.focusCleanup&&!this.blockFocusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,t,this.settings.errorClass,this.settings.validClass),this.addWrapper(this.errorsFor(t)).hide())},onfocusout:function(t){this.checkable(t)||!(t.name in this.submitted)&&this.optional(t)||this.element(t)},onkeyup:function(t,e){(9!==e.which||""!==this.elementValue(t))&&(t.name in this.submitted||t===this.lastElement)&&this.element(t)},onclick:function(t){t.name in this.submitted?this.element(t):t.parentNode.name in this.submitted&&this.element(t.parentNode)},highlight:function(e,i,s){"radio"===e.type?this.findByName(e.name).addClass(i).removeClass(s):t(e).addClass(i).removeClass(s)},unhighlight:function(e,i,s){"radio"===e.type?this.findByName(e.name).removeClass(i).addClass(s):t(e).removeClass(i).addClass(s)}},setDefaults:function(e){t.extend(t.validator.defaults,e)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",maxlength:t.validator.format("Please enter no more than {0} characters."),minlength:t.validator.format("Please enter at least {0} characters."),rangelength:t.validator.format("Please enter a value between {0} and {1} characters long."),range:t.validator.format("Please enter a value between {0} and {1}."),max:t.validator.format("Please enter a value less than or equal to {0}."),min:t.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:!1,prototype:{init:function(){function e(e){var i=t.data(this[0].form,"validator"),s="on"+e.type.replace(/^validate/,"");i.settings[s]&&i.settings[s].call(i,this[0],e)}this.labelContainer=t(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||t(this.currentForm),this.containers=t(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var i=this.groups={};t.each(this.settings.groups,function(e,s){"string"==typeof s&&(s=s.split(/\s/)),t.each(s,function(t,s){i[s]=e})});var s=this.settings.rules;t.each(s,function(e,i){s[e]=t.validator.normalizeRule(i)}),t(this.currentForm).validateDelegate(":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'] ,[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'] ","focusin focusout keyup",e).validateDelegate("[type='radio'], [type='checkbox'], select, option","click",e),this.settings.invalidHandler&&t(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler)},form:function(){return this.checkForm(),t.extend(this.submitted,this.errorMap),this.invalid=t.extend({},this.errorMap),this.valid()||t(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var t=0,e=this.currentElements=this.elements();e[t];t++)this.check(e[t]);return this.valid()},element:function(e){e=this.validationTargetFor(this.clean(e)),this.lastElement=e,this.prepareElement(e),this.currentElements=t(e);var i=this.check(e)!==!1;return i?delete this.invalid[e.name]:this.invalid[e.name]=!0,this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),i},showErrors:function(e){if(e){t.extend(this.errorMap,e),this.errorList=[];for(var i in e)this.errorList.push({message:e[i],element:this.findByName(i)[0]});this.successList=t.grep(this.successList,function(t){return!(t.name in e)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){t.fn.resetForm&&t(this.currentForm).resetForm(),this.submitted={},this.lastElement=null,this.prepareForm(),this.hideErrors(),this.elements().removeClass(this.settings.errorClass).removeData("previousValue")},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(t){var e=0;for(var i in t)e++;return e},hideErrors:function(){this.addWrapper(this.toHide).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{t(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(e){}},findLastActive:function(){var e=this.lastActive;return e&&1===t.grep(this.errorList,function(t){return t.element.name===e.name}).length&&e},elements:function(){var e=this,i={};return t(this.currentForm).find("input, select, textarea").not(":submit, :reset, :image, [disabled]").not(this.settings.ignore).filter(function(){return!this.name&&e.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.name in i||!e.objectLength(t(this).rules())?!1:(i[this.name]=!0,!0)})},clean:function(e){return t(e)[0]},errors:function(){var e=this.settings.errorClass.replace(" ",".");return t(this.settings.errorElement+"."+e,this.errorContext)},reset:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=t([]),this.toHide=t([]),this.currentElements=t([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(t){this.reset(),this.toHide=this.errorsFor(t)},elementValue:function(e){var i=t(e).attr("type"),s=t(e).val();return"radio"===i||"checkbox"===i?t("input[name='"+t(e).attr("name")+"']:checked").val():"string"==typeof s?s.replace(/\r/g,""):s},check:function(e){e=this.validationTargetFor(this.clean(e));var i,s=t(e).rules(),r=!1,n=this.elementValue(e);for(var a in s){var u={method:a,parameters:s[a]};try{if(i=t.validator.methods[a].call(this,n,e,u.parameters),"dependency-mismatch"===i){r=!0;continue}if(r=!1,"pending"===i)return this.toHide=this.toHide.not(this.errorsFor(e)),void 0;if(!i)return this.formatAndAdd(e,u),!1}catch(o){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+e.id+", check the '"+u.method+"' method.",o),o}}return r?void 0:(this.objectLength(s)&&this.successList.push(e),!0)},customDataMessage:function(e,i){return t(e).data("msg-"+i.toLowerCase())||e.attributes&&t(e).attr("data-msg-"+i.toLowerCase())},customMessage:function(t,e){var i=this.settings.messages[t];return i&&(i.constructor===String?i:i[e])},findDefined:function(){for(var t=0;arguments.length>t;t++)if(void 0!==arguments[t])return arguments[t];return void 0},defaultMessage:function(e,i){return this.findDefined(this.customMessage(e.name,i),this.customDataMessage(e,i),!this.settings.ignoreTitle&&e.title||void 0,t.validator.messages[i],"Warning: No message defined for "+e.name+"")},formatAndAdd:function(e,i){var s=this.defaultMessage(e,i.method),r=/\$?\{(\d+)\}/g;"function"==typeof s?s=s.call(this,i.parameters,e):r.test(s)&&(s=t.validator.format(s.replace(r,"{$1}"),i.parameters)),this.errorList.push({message:s,element:e}),this.errorMap[e.name]=s,this.submitted[e.name]=s},addWrapper:function(t){return this.settings.wrapper&&(t=t.add(t.parent(this.settings.wrapper))),t},defaultShowErrors:function(){var t,e;for(t=0;this.errorList[t];t++){var i=this.errorList[t];this.settings.highlight&&this.settings.highlight.call(this,i.element,this.settings.errorClass,this.settings.validClass),this.showLabel(i.element,i.message)}if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(t=0;this.successList[t];t++)this.showLabel(this.successList[t]);if(this.settings.unhighlight)for(t=0,e=this.validElements();e[t];t++)this.settings.unhighlight.call(this,e[t],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return t(this.errorList).map(function(){return this.element})},showLabel:function(e,i){var s=this.errorsFor(e);s.length?(s.removeClass(this.settings.validClass).addClass(this.settings.errorClass),s.html(i)):(s=t("<"+this.settings.errorElement+">").attr("for",this.idOrName(e)).addClass(this.settings.errorClass).html(i||""),this.settings.wrapper&&(s=s.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.append(s).length||(this.settings.errorPlacement?this.settings.errorPlacement(s,t(e)):s.insertAfter(e))),!i&&this.settings.success&&(s.text(""),"string"==typeof this.settings.success?s.addClass(this.settings.success):this.settings.success(s,e)),this.toShow=this.toShow.add(s)},errorsFor:function(e){var i=this.idOrName(e);return this.errors().filter(function(){return t(this).attr("for")===i})},idOrName:function(t){return this.groups[t.name]||(this.checkable(t)?t.name:t.id||t.name)},validationTargetFor:function(t){return this.checkable(t)&&(t=this.findByName(t.name).not(this.settings.ignore)[0]),t},checkable:function(t){return/radio|checkbox/i.test(t.type)},findByName:function(e){return t(this.currentForm).find("[name='"+e+"']")},getLength:function(e,i){switch(i.nodeName.toLowerCase()){case"select":return t("option:selected",i).length;case"input":if(this.checkable(i))return this.findByName(i.name).filter(":checked").length}return e.length},depend:function(t,e){return this.dependTypes[typeof t]?this.dependTypes[typeof t](t,e):!0},dependTypes:{"boolean":function(t){return t},string:function(e,i){return!!t(e,i.form).length},"function":function(t,e){return t(e)}},optional:function(e){var i=this.elementValue(e);return!t.validator.methods.required.call(this,i,e)&&"dependency-mismatch"},startRequest:function(t){this.pending[t.name]||(this.pendingRequest++,this.pending[t.name]=!0)},stopRequest:function(e,i){this.pendingRequest--,0>this.pendingRequest&&(this.pendingRequest=0),delete this.pending[e.name],i&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(t(this.currentForm).submit(),this.formSubmitted=!1):!i&&0===this.pendingRequest&&this.formSubmitted&&(t(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(e){return t.data(e,"previousValue")||t.data(e,"previousValue",{old:null,valid:!0,message:this.defaultMessage(e,"remote")})}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(e,i){e.constructor===String?this.classRuleSettings[e]=i:t.extend(this.classRuleSettings,e)},classRules:function(e){var i={},s=t(e).attr("class");return s&&t.each(s.split(" "),function(){this in t.validator.classRuleSettings&&t.extend(i,t.validator.classRuleSettings[this])}),i},attributeRules:function(e){var i={},s=t(e),r=s[0].getAttribute("type");for(var n in t.validator.methods){var a;"required"===n?(a=s.get(0).getAttribute(n),""===a&&(a=!0),a=!!a):a=s.attr(n),/min|max/.test(n)&&(null===r||/number|range|text/.test(r))&&(a=Number(a)),a?i[n]=a:r===n&&"range"!==r&&(i[n]=!0)}return i.maxlength&&/-1|2147483647|524288/.test(i.maxlength)&&delete i.maxlength,i},dataRules:function(e){var i,s,r={},n=t(e);for(i in t.validator.methods)s=n.data("rule-"+i.toLowerCase()),void 0!==s&&(r[i]=s);return r},staticRules:function(e){var i={},s=t.data(e.form,"validator");return s.settings.rules&&(i=t.validator.normalizeRule(s.settings.rules[e.name])||{}),i},normalizeRules:function(e,i){return t.each(e,function(s,r){if(r===!1)return delete e[s],void 0;if(r.param||r.depends){var n=!0;switch(typeof r.depends){case"string":n=!!t(r.depends,i.form).length;break;case"function":n=r.depends.call(i,i)}n?e[s]=void 0!==r.param?r.param:!0:delete e[s]}}),t.each(e,function(s,r){e[s]=t.isFunction(r)?r(i):r}),t.each(["minlength","maxlength"],function(){e[this]&&(e[this]=Number(e[this]))}),t.each(["rangelength","range"],function(){var i;e[this]&&(t.isArray(e[this])?e[this]=[Number(e[this][0]),Number(e[this][1])]:"string"==typeof e[this]&&(i=e[this].split(/[\s,]+/),e[this]=[Number(i[0]),Number(i[1])]))}),t.validator.autoCreateRanges&&(e.min&&e.max&&(e.range=[e.min,e.max],delete e.min,delete e.max),e.minlength&&e.maxlength&&(e.rangelength=[e.minlength,e.maxlength],delete e.minlength,delete e.maxlength)),e},normalizeRule:function(e){if("string"==typeof e){var i={};t.each(e.split(/\s/),function(){i[this]=!0}),e=i}return e},addMethod:function(e,i,s){t.validator.methods[e]=i,t.validator.messages[e]=void 0!==s?s:t.validator.messages[e],3>i.length&&t.validator.addClassRules(e,t.validator.normalizeRule(e))},methods:{required:function(e,i,s){if(!this.depend(s,i))return"dependency-mismatch";if("select"===i.nodeName.toLowerCase()){var r=t(i).val();return r&&r.length>0}return this.checkable(i)?this.getLength(e,i)>0:t.trim(e).length>0},email:function(t,e){return this.optional(e)||/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(t)},url:function(t,e){return this.optional(e)||/^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(t)},date:function(t,e){return this.optional(e)||!/Invalid|NaN/.test(""+new Date(t))},dateISO:function(t,e){return this.optional(e)||/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(t)},number:function(t,e){return this.optional(e)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(t)},digits:function(t,e){return this.optional(e)||/^\d+$/.test(t)},creditcard:function(t,e){if(this.optional(e))return"dependency-mismatch";if(/[^0-9 \-]+/.test(t))return!1;var i=0,s=0,r=!1;t=t.replace(/\D/g,"");for(var n=t.length-1;n>=0;n--){var a=t.charAt(n);s=parseInt(a,10),r&&(s*=2)>9&&(s-=9),i+=s,r=!r}return 0===i%10},minlength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||r>=s},maxlength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||s>=r},rangelength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||r>=s[0]&&s[1]>=r},min:function(t,e,i){return this.optional(e)||t>=i},max:function(t,e,i){return this.optional(e)||i>=t},range:function(t,e,i){return this.optional(e)||t>=i[0]&&i[1]>=t},equalTo:function(e,i,s){var r=t(s);return this.settings.onfocusout&&r.unbind(".validate-equalTo").bind("blur.validate-equalTo",function(){t(i).valid()}),e===r.val()},remote:function(e,i,s){if(this.optional(i))return"dependency-mismatch";var r=this.previousValue(i);if(this.settings.messages[i.name]||(this.settings.messages[i.name]={}),r.originalMessage=this.settings.messages[i.name].remote,this.settings.messages[i.name].remote=r.message,s="string"==typeof s&&{url:s}||s,r.old===e)return r.valid;r.old=e;var n=this;this.startRequest(i);var a={};return a[i.name]=e,t.ajax(t.extend(!0,{url:s,mode:"abort",port:"validate"+i.name,dataType:"json",data:a,success:function(s){n.settings.messages[i.name].remote=r.originalMessage;var a=s===!0||"true"===s;if(a){var u=n.formSubmitted;n.prepareElement(i),n.formSubmitted=u,n.successList.push(i),delete n.invalid[i.name],n.showErrors()}else{var o={},l=s||n.defaultMessage(i,"remote");o[i.name]=r.message=t.isFunction(l)?l(e):l,n.invalid[i.name]=!0,n.showErrors(o)}r.valid=a,n.stopRequest(i,a)}},s)),"pending"}}}),t.format=t.validator.format})(jQuery),function(t){var e={};if(t.ajaxPrefilter)t.ajaxPrefilter(function(t,i,s){var r=t.port;"abort"===t.mode&&(e[r]&&e[r].abort(),e[r]=s)});else{var i=t.ajax;t.ajax=function(s){var r=("mode"in s?s:t.ajaxSettings).mode,n=("port"in s?s:t.ajaxSettings).port;return"abort"===r?(e[n]&&e[n].abort(),e[n]=i.apply(this,arguments),e[n]):i.apply(this,arguments)}}}(jQuery),function(t){t.extend(t.fn,{validateDelegate:function(e,i,s){return this.bind(i,function(i){var r=t(i.target);return r.is(e)?s.apply(r,arguments):void 0})}})}(jQuery); -------------------------------------------------------------------------------- /ChatApplication/Scripts/jquery.validate.unobtrusive.js: -------------------------------------------------------------------------------- 1 | /* NUGET: BEGIN LICENSE TEXT 2 | * 3 | * Microsoft grants you the right to use these script files for the sole 4 | * purpose of either: (i) interacting through your browser with the Microsoft 5 | * website or online service, subject to the applicable licensing or use 6 | * terms; or (ii) using the files as included with a Microsoft product subject 7 | * to that product's license terms. Microsoft reserves all other rights to the 8 | * files not expressly granted by Microsoft, whether by implication, estoppel 9 | * or otherwise. Insofar as a script file is dual licensed under GPL, 10 | * Microsoft neither took the code under GPL nor distributes it thereunder but 11 | * under the terms set out in this paragraph. All notices and licenses 12 | * below are for informational purposes only. 13 | * 14 | * NUGET: END LICENSE TEXT */ 15 | /*! 16 | ** Unobtrusive validation support library for jQuery and jQuery Validate 17 | ** Copyright (C) Microsoft Corporation. All rights reserved. 18 | */ 19 | 20 | /*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */ 21 | /*global document: false, jQuery: false */ 22 | 23 | (function ($) { 24 | var $jQval = $.validator, 25 | adapters, 26 | data_validation = "unobtrusiveValidation"; 27 | 28 | function setValidationValues(options, ruleName, value) { 29 | options.rules[ruleName] = value; 30 | if (options.message) { 31 | options.messages[ruleName] = options.message; 32 | } 33 | } 34 | 35 | function splitAndTrim(value) { 36 | return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g); 37 | } 38 | 39 | function escapeAttributeValue(value) { 40 | // As mentioned on http://api.jquery.com/category/selectors/ 41 | return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1"); 42 | } 43 | 44 | function getModelPrefix(fieldName) { 45 | return fieldName.substr(0, fieldName.lastIndexOf(".") + 1); 46 | } 47 | 48 | function appendModelPrefix(value, prefix) { 49 | if (value.indexOf("*.") === 0) { 50 | value = value.replace("*.", prefix); 51 | } 52 | return value; 53 | } 54 | 55 | function onError(error, inputElement) { // 'this' is the form element 56 | var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"), 57 | replaceAttrValue = container.attr("data-valmsg-replace"), 58 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null; 59 | 60 | container.removeClass("field-validation-valid").addClass("field-validation-error"); 61 | error.data("unobtrusiveContainer", container); 62 | 63 | if (replace) { 64 | container.empty(); 65 | error.removeClass("input-validation-error").appendTo(container); 66 | } 67 | else { 68 | error.hide(); 69 | } 70 | } 71 | 72 | function onErrors(event, validator) { // 'this' is the form element 73 | var container = $(this).find("[data-valmsg-summary=true]"), 74 | list = container.find("ul"); 75 | 76 | if (list && list.length && validator.errorList.length) { 77 | list.empty(); 78 | container.addClass("validation-summary-errors").removeClass("validation-summary-valid"); 79 | 80 | $.each(validator.errorList, function () { 81 | $("
  • ").html(this.message).appendTo(list); 82 | }); 83 | } 84 | } 85 | 86 | function onSuccess(error) { // 'this' is the form element 87 | var container = error.data("unobtrusiveContainer"), 88 | replaceAttrValue = container.attr("data-valmsg-replace"), 89 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null; 90 | 91 | if (container) { 92 | container.addClass("field-validation-valid").removeClass("field-validation-error"); 93 | error.removeData("unobtrusiveContainer"); 94 | 95 | if (replace) { 96 | container.empty(); 97 | } 98 | } 99 | } 100 | 101 | function onReset(event) { // 'this' is the form element 102 | var $form = $(this), 103 | key = '__jquery_unobtrusive_validation_form_reset'; 104 | if ($form.data(key)) { 105 | return; 106 | } 107 | // Set a flag that indicates we're currently resetting the form. 108 | $form.data(key, true); 109 | try { 110 | $form.data("validator").resetForm(); 111 | } finally { 112 | $form.removeData(key); 113 | } 114 | 115 | $form.find(".validation-summary-errors") 116 | .addClass("validation-summary-valid") 117 | .removeClass("validation-summary-errors"); 118 | $form.find(".field-validation-error") 119 | .addClass("field-validation-valid") 120 | .removeClass("field-validation-error") 121 | .removeData("unobtrusiveContainer") 122 | .find(">*") // If we were using valmsg-replace, get the underlying error 123 | .removeData("unobtrusiveContainer"); 124 | } 125 | 126 | function validationInfo(form) { 127 | var $form = $(form), 128 | result = $form.data(data_validation), 129 | onResetProxy = $.proxy(onReset, form), 130 | defaultOptions = $jQval.unobtrusive.options || {}, 131 | execInContext = function (name, args) { 132 | var func = defaultOptions[name]; 133 | func && $.isFunction(func) && func.apply(form, args); 134 | } 135 | 136 | if (!result) { 137 | result = { 138 | options: { // options structure passed to jQuery Validate's validate() method 139 | errorClass: defaultOptions.errorClass || "input-validation-error", 140 | errorElement: defaultOptions.errorElement || "span", 141 | errorPlacement: function () { 142 | onError.apply(form, arguments); 143 | execInContext("errorPlacement", arguments); 144 | }, 145 | invalidHandler: function () { 146 | onErrors.apply(form, arguments); 147 | execInContext("invalidHandler", arguments); 148 | }, 149 | messages: {}, 150 | rules: {}, 151 | success: function () { 152 | onSuccess.apply(form, arguments); 153 | execInContext("success", arguments); 154 | } 155 | }, 156 | attachValidation: function () { 157 | $form 158 | .off("reset." + data_validation, onResetProxy) 159 | .on("reset." + data_validation, onResetProxy) 160 | .validate(this.options); 161 | }, 162 | validate: function () { // a validation function that is called by unobtrusive Ajax 163 | $form.validate(); 164 | return $form.valid(); 165 | } 166 | }; 167 | $form.data(data_validation, result); 168 | } 169 | 170 | return result; 171 | } 172 | 173 | $jQval.unobtrusive = { 174 | adapters: [], 175 | 176 | parseElement: function (element, skipAttach) { 177 | /// 178 | /// Parses a single HTML element for unobtrusive validation attributes. 179 | /// 180 | /// The HTML element to be parsed. 181 | /// [Optional] true to skip attaching the 182 | /// validation to the form. If parsing just this single element, you should specify true. 183 | /// If parsing several elements, you should specify false, and manually attach the validation 184 | /// to the form when you are finished. The default is false. 185 | var $element = $(element), 186 | form = $element.parents("form")[0], 187 | valInfo, rules, messages; 188 | 189 | if (!form) { // Cannot do client-side validation without a form 190 | return; 191 | } 192 | 193 | valInfo = validationInfo(form); 194 | valInfo.options.rules[element.name] = rules = {}; 195 | valInfo.options.messages[element.name] = messages = {}; 196 | 197 | $.each(this.adapters, function () { 198 | var prefix = "data-val-" + this.name, 199 | message = $element.attr(prefix), 200 | paramValues = {}; 201 | 202 | if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy) 203 | prefix += "-"; 204 | 205 | $.each(this.params, function () { 206 | paramValues[this] = $element.attr(prefix + this); 207 | }); 208 | 209 | this.adapt({ 210 | element: element, 211 | form: form, 212 | message: message, 213 | params: paramValues, 214 | rules: rules, 215 | messages: messages 216 | }); 217 | } 218 | }); 219 | 220 | $.extend(rules, { "__dummy__": true }); 221 | 222 | if (!skipAttach) { 223 | valInfo.attachValidation(); 224 | } 225 | }, 226 | 227 | parse: function (selector) { 228 | /// 229 | /// Parses all the HTML elements in the specified selector. It looks for input elements decorated 230 | /// with the [data-val=true] attribute value and enables validation according to the data-val-* 231 | /// attribute values. 232 | /// 233 | /// Any valid jQuery selector. 234 | 235 | // $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one 236 | // element with data-val=true 237 | var $selector = $(selector), 238 | $forms = $selector.parents() 239 | .addBack() 240 | .filter("form") 241 | .add($selector.find("form")) 242 | .has("[data-val=true]"); 243 | 244 | $selector.find("[data-val=true]").each(function () { 245 | $jQval.unobtrusive.parseElement(this, true); 246 | }); 247 | 248 | $forms.each(function () { 249 | var info = validationInfo(this); 250 | if (info) { 251 | info.attachValidation(); 252 | } 253 | }); 254 | } 255 | }; 256 | 257 | adapters = $jQval.unobtrusive.adapters; 258 | 259 | adapters.add = function (adapterName, params, fn) { 260 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation. 261 | /// The name of the adapter to be added. This matches the name used 262 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 263 | /// [Optional] An array of parameter names (strings) that will 264 | /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and 265 | /// mmmm is the parameter name). 266 | /// The function to call, which adapts the values from the HTML 267 | /// attributes into jQuery Validate rules and/or messages. 268 | /// 269 | if (!fn) { // Called with no params, just a function 270 | fn = params; 271 | params = []; 272 | } 273 | this.push({ name: adapterName, params: params, adapt: fn }); 274 | return this; 275 | }; 276 | 277 | adapters.addBool = function (adapterName, ruleName) { 278 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 279 | /// the jQuery Validate validation rule has no parameter values. 280 | /// The name of the adapter to be added. This matches the name used 281 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 282 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value 283 | /// of adapterName will be used instead. 284 | /// 285 | return this.add(adapterName, function (options) { 286 | setValidationValues(options, ruleName || adapterName, true); 287 | }); 288 | }; 289 | 290 | adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) { 291 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 292 | /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and 293 | /// one for min-and-max). The HTML parameters are expected to be named -min and -max. 294 | /// The name of the adapter to be added. This matches the name used 295 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 296 | /// The name of the jQuery Validate rule to be used when you only 297 | /// have a minimum value. 298 | /// The name of the jQuery Validate rule to be used when you only 299 | /// have a maximum value. 300 | /// The name of the jQuery Validate rule to be used when you 301 | /// have both a minimum and maximum value. 302 | /// [Optional] The name of the HTML attribute that 303 | /// contains the minimum value. The default is "min". 304 | /// [Optional] The name of the HTML attribute that 305 | /// contains the maximum value. The default is "max". 306 | /// 307 | return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) { 308 | var min = options.params.min, 309 | max = options.params.max; 310 | 311 | if (min && max) { 312 | setValidationValues(options, minMaxRuleName, [min, max]); 313 | } 314 | else if (min) { 315 | setValidationValues(options, minRuleName, min); 316 | } 317 | else if (max) { 318 | setValidationValues(options, maxRuleName, max); 319 | } 320 | }); 321 | }; 322 | 323 | adapters.addSingleVal = function (adapterName, attribute, ruleName) { 324 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 325 | /// the jQuery Validate validation rule has a single value. 326 | /// The name of the adapter to be added. This matches the name used 327 | /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name). 328 | /// [Optional] The name of the HTML attribute that contains the value. 329 | /// The default is "val". 330 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value 331 | /// of adapterName will be used instead. 332 | /// 333 | return this.add(adapterName, [attribute || "val"], function (options) { 334 | setValidationValues(options, ruleName || adapterName, options.params[attribute]); 335 | }); 336 | }; 337 | 338 | $jQval.addMethod("__dummy__", function (value, element, params) { 339 | return true; 340 | }); 341 | 342 | $jQval.addMethod("regex", function (value, element, params) { 343 | var match; 344 | if (this.optional(element)) { 345 | return true; 346 | } 347 | 348 | match = new RegExp(params).exec(value); 349 | return (match && (match.index === 0) && (match[0].length === value.length)); 350 | }); 351 | 352 | $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) { 353 | var match; 354 | if (nonalphamin) { 355 | match = value.match(/\W/g); 356 | match = match && match.length >= nonalphamin; 357 | } 358 | return match; 359 | }); 360 | 361 | if ($jQval.methods.extension) { 362 | adapters.addSingleVal("accept", "mimtype"); 363 | adapters.addSingleVal("extension", "extension"); 364 | } else { 365 | // for backward compatibility, when the 'extension' validation method does not exist, such as with versions 366 | // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for 367 | // validating the extension, and ignore mime-type validations as they are not supported. 368 | adapters.addSingleVal("extension", "extension", "accept"); 369 | } 370 | 371 | adapters.addSingleVal("regex", "pattern"); 372 | adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"); 373 | adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range"); 374 | adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength"); 375 | adapters.add("equalto", ["other"], function (options) { 376 | var prefix = getModelPrefix(options.element.name), 377 | other = options.params.other, 378 | fullOtherName = appendModelPrefix(other, prefix), 379 | element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0]; 380 | 381 | setValidationValues(options, "equalTo", element); 382 | }); 383 | adapters.add("required", function (options) { 384 | // jQuery Validate equates "required" with "mandatory" for checkbox elements 385 | if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") { 386 | setValidationValues(options, "required", true); 387 | } 388 | }); 389 | adapters.add("remote", ["url", "type", "additionalfields"], function (options) { 390 | var value = { 391 | url: options.params.url, 392 | type: options.params.type || "GET", 393 | data: {} 394 | }, 395 | prefix = getModelPrefix(options.element.name); 396 | 397 | $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) { 398 | var paramName = appendModelPrefix(fieldName, prefix); 399 | value.data[paramName] = function () { 400 | var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']"); 401 | // For checkboxes and radio buttons, only pick up values from checked fields. 402 | if (field.is(":checkbox")) { 403 | return field.filter(":checked").val() || field.filter(":hidden").val() || ''; 404 | } 405 | else if (field.is(":radio")) { 406 | return field.filter(":checked").val() || ''; 407 | } 408 | return field.val(); 409 | }; 410 | }); 411 | 412 | setValidationValues(options, "remote", value); 413 | }); 414 | adapters.add("password", ["min", "nonalphamin", "regex"], function (options) { 415 | if (options.params.min) { 416 | setValidationValues(options, "minlength", options.params.min); 417 | } 418 | if (options.params.nonalphamin) { 419 | setValidationValues(options, "nonalphamin", options.params.nonalphamin); 420 | } 421 | if (options.params.regex) { 422 | setValidationValues(options, "regex", options.params.regex); 423 | } 424 | }); 425 | 426 | $(function () { 427 | $jQval.unobtrusive.parse(document); 428 | }); 429 | }(jQuery)); -------------------------------------------------------------------------------- /ChatApplication/Scripts/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | /* NUGET: BEGIN LICENSE TEXT 2 | * 3 | * Microsoft grants you the right to use these script files for the sole 4 | * purpose of either: (i) interacting through your browser with the Microsoft 5 | * website or online service, subject to the applicable licensing or use 6 | * terms; or (ii) using the files as included with a Microsoft product subject 7 | * to that product's license terms. Microsoft reserves all other rights to the 8 | * files not expressly granted by Microsoft, whether by implication, estoppel 9 | * or otherwise. Insofar as a script file is dual licensed under GPL, 10 | * Microsoft neither took the code under GPL nor distributes it thereunder but 11 | * under the terms set out in this paragraph. All notices and licenses 12 | * below are for informational purposes only. 13 | * 14 | * NUGET: END LICENSE TEXT */ 15 | /* 16 | ** Unobtrusive validation support library for jQuery and jQuery Validate 17 | ** Copyright (C) Microsoft Corporation. All rights reserved. 18 | */ 19 | (function(a){var d=a.validator,b,e="unobtrusiveValidation";function c(a,b,c){a.rules[b]=c;if(a.message)a.messages[b]=a.message}function j(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function f(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function h(a){return a.substr(0,a.lastIndexOf(".")+1)}function g(a,b){if(a.indexOf("*.")===0)a=a.replace("*.",b);return a}function m(c,e){var b=a(this).find("[data-valmsg-for='"+f(e[0].name)+"']"),d=b.attr("data-valmsg-replace"),g=d?a.parseJSON(d)!==false:null;b.removeClass("field-validation-valid").addClass("field-validation-error");c.data("unobtrusiveContainer",b);if(g){b.empty();c.removeClass("input-validation-error").appendTo(b)}else c.hide()}function l(e,d){var c=a(this).find("[data-valmsg-summary=true]"),b=c.find("ul");if(b&&b.length&&d.errorList.length){b.empty();c.addClass("validation-summary-errors").removeClass("validation-summary-valid");a.each(d.errorList,function(){a("
  • ").html(this.message).appendTo(b)})}}function k(d){var b=d.data("unobtrusiveContainer"),c=b.attr("data-valmsg-replace"),e=c?a.parseJSON(c):null;if(b){b.addClass("field-validation-valid").removeClass("field-validation-error");d.removeData("unobtrusiveContainer");e&&b.empty()}}function n(){var b=a(this),c="__jquery_unobtrusive_validation_form_reset";if(b.data(c))return;b.data(c,true);try{b.data("validator").resetForm()}finally{b.removeData(c)}b.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors");b.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}function i(b){var c=a(b),f=c.data(e),i=a.proxy(n,b),g=d.unobtrusive.options||{},h=function(e,d){var c=g[e];c&&a.isFunction(c)&&c.apply(b,d)};if(!f){f={options:{errorClass:g.errorClass||"input-validation-error",errorElement:g.errorElement||"span",errorPlacement:function(){m.apply(b,arguments);h("errorPlacement",arguments)},invalidHandler:function(){l.apply(b,arguments);h("invalidHandler",arguments)},messages:{},rules:{},success:function(){k.apply(b,arguments);h("success",arguments)}},attachValidation:function(){c.off("reset."+e,i).on("reset."+e,i).validate(this.options)},validate:function(){c.validate();return c.valid()}};c.data(e,f)}return f}d.unobtrusive={adapters:[],parseElement:function(b,h){var d=a(b),f=d.parents("form")[0],c,e,g;if(!f)return;c=i(f);c.options.rules[b.name]=e={};c.options.messages[b.name]=g={};a.each(this.adapters,function(){var c="data-val-"+this.name,i=d.attr(c),h={};if(i!==undefined){c+="-";a.each(this.params,function(){h[this]=d.attr(c+this)});this.adapt({element:b,form:f,message:i,params:h,rules:e,messages:g})}});a.extend(e,{__dummy__:true});!h&&c.attachValidation()},parse:function(c){var b=a(c),e=b.parents().addBack().filter("form").add(b.find("form")).has("[data-val=true]");b.find("[data-val=true]").each(function(){d.unobtrusive.parseElement(this,true)});e.each(function(){var a=i(this);a&&a.attachValidation()})}};b=d.unobtrusive.adapters;b.add=function(c,a,b){if(!b){b=a;a=[]}this.push({name:c,params:a,adapt:b});return this};b.addBool=function(a,b){return this.add(a,function(d){c(d,b||a,true)})};b.addMinMax=function(e,g,f,a,d,b){return this.add(e,[d||"min",b||"max"],function(b){var e=b.params.min,d=b.params.max;if(e&&d)c(b,a,[e,d]);else if(e)c(b,g,e);else d&&c(b,f,d)})};b.addSingleVal=function(a,b,d){return this.add(a,[b||"val"],function(e){c(e,d||a,e.params[b])})};d.addMethod("__dummy__",function(){return true});d.addMethod("regex",function(b,c,d){var a;if(this.optional(c))return true;a=(new RegExp(d)).exec(b);return a&&a.index===0&&a[0].length===b.length});d.addMethod("nonalphamin",function(c,d,b){var a;if(b){a=c.match(/\W/g);a=a&&a.length>=b}return a});if(d.methods.extension){b.addSingleVal("accept","mimtype");b.addSingleVal("extension","extension")}else b.addSingleVal("extension","extension","accept");b.addSingleVal("regex","pattern");b.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");b.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range");b.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength");b.add("equalto",["other"],function(b){var i=h(b.element.name),j=b.params.other,d=g(j,i),e=a(b.form).find(":input").filter("[name='"+f(d)+"']")[0];c(b,"equalTo",e)});b.add("required",function(a){(a.element.tagName.toUpperCase()!=="INPUT"||a.element.type.toUpperCase()!=="CHECKBOX")&&c(a,"required",true)});b.add("remote",["url","type","additionalfields"],function(b){var d={url:b.params.url,type:b.params.type||"GET",data:{}},e=h(b.element.name);a.each(j(b.params.additionalfields||b.element.name),function(i,h){var c=g(h,e);d.data[c]=function(){var d=a(b.form).find(":input").filter("[name='"+f(c)+"']");return d.is(":checkbox")?d.filter(":checked").val()||d.filter(":hidden").val()||"":d.is(":radio")?d.filter(":checked").val()||"":d.val()}});c(b,"remote",d)});b.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&c(a,"minlength",a.params.min);a.params.nonalphamin&&c(a,"nonalphamin",a.params.nonalphamin);a.params.regex&&c(a,"regex",a.params.regex)});a(function(){d.unobtrusive.parse(document)})})(jQuery); -------------------------------------------------------------------------------- /ChatApplication/Scripts/respond.js: -------------------------------------------------------------------------------- 1 | /* NUGET: BEGIN LICENSE TEXT 2 | * 3 | * Microsoft grants you the right to use these script files for the sole 4 | * purpose of either: (i) interacting through your browser with the Microsoft 5 | * website or online service, subject to the applicable licensing or use 6 | * terms; or (ii) using the files as included with a Microsoft product subject 7 | * to that product's license terms. Microsoft reserves all other rights to the 8 | * files not expressly granted by Microsoft, whether by implication, estoppel 9 | * or otherwise. Insofar as a script file is dual licensed under GPL, 10 | * Microsoft neither took the code under GPL nor distributes it thereunder but 11 | * under the terms set out in this paragraph. All notices and licenses 12 | * below are for informational purposes only. 13 | * 14 | * NUGET: END LICENSE TEXT */ 15 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */ 16 | /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */ 17 | window.matchMedia = window.matchMedia || (function(doc, undefined){ 18 | 19 | var bool, 20 | docElem = doc.documentElement, 21 | refNode = docElem.firstElementChild || docElem.firstChild, 22 | // fakeBody required for 23 | fakeBody = doc.createElement('body'), 24 | div = doc.createElement('div'); 25 | 26 | div.id = 'mq-test-1'; 27 | div.style.cssText = "position:absolute;top:-100em"; 28 | fakeBody.style.background = "none"; 29 | fakeBody.appendChild(div); 30 | 31 | return function(q){ 32 | 33 | div.innerHTML = '­'; 34 | 35 | docElem.insertBefore(fakeBody, refNode); 36 | bool = div.offsetWidth == 42; 37 | docElem.removeChild(fakeBody); 38 | 39 | return { matches: bool, media: q }; 40 | }; 41 | 42 | })(document); 43 | 44 | 45 | 46 | 47 | /*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 48 | (function( win ){ 49 | //exposed namespace 50 | win.respond = {}; 51 | 52 | //define update even in native-mq-supporting browsers, to avoid errors 53 | respond.update = function(){}; 54 | 55 | //expose media query support flag for external use 56 | respond.mediaQueriesSupported = win.matchMedia && win.matchMedia( "only all" ).matches; 57 | 58 | //if media queries are supported, exit here 59 | if( respond.mediaQueriesSupported ){ return; } 60 | 61 | //define vars 62 | var doc = win.document, 63 | docElem = doc.documentElement, 64 | mediastyles = [], 65 | rules = [], 66 | appendedEls = [], 67 | parsedSheets = {}, 68 | resizeThrottle = 30, 69 | head = doc.getElementsByTagName( "head" )[0] || docElem, 70 | base = doc.getElementsByTagName( "base" )[0], 71 | links = head.getElementsByTagName( "link" ), 72 | requestQueue = [], 73 | 74 | //loop stylesheets, send text content to translate 75 | ripCSS = function(){ 76 | var sheets = links, 77 | sl = sheets.length, 78 | i = 0, 79 | //vars for loop: 80 | sheet, href, media, isCSS; 81 | 82 | for( ; i < sl; i++ ){ 83 | sheet = sheets[ i ], 84 | href = sheet.href, 85 | media = sheet.media, 86 | isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet"; 87 | 88 | //only links plz and prevent re-parsing 89 | if( !!href && isCSS && !parsedSheets[ href ] ){ 90 | // selectivizr exposes css through the rawCssText expando 91 | if (sheet.styleSheet && sheet.styleSheet.rawCssText) { 92 | translate( sheet.styleSheet.rawCssText, href, media ); 93 | parsedSheets[ href ] = true; 94 | } else { 95 | if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base) 96 | || href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){ 97 | requestQueue.push( { 98 | href: href, 99 | media: media 100 | } ); 101 | } 102 | } 103 | } 104 | } 105 | makeRequests(); 106 | }, 107 | 108 | //recurse through request queue, get css text 109 | makeRequests = function(){ 110 | if( requestQueue.length ){ 111 | var thisRequest = requestQueue.shift(); 112 | 113 | ajax( thisRequest.href, function( styles ){ 114 | translate( styles, thisRequest.href, thisRequest.media ); 115 | parsedSheets[ thisRequest.href ] = true; 116 | makeRequests(); 117 | } ); 118 | } 119 | }, 120 | 121 | //find media blocks in css text, convert to style blocks 122 | translate = function( styles, href, media ){ 123 | var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ), 124 | ql = qs && qs.length || 0, 125 | //try to get CSS path 126 | href = href.substring( 0, href.lastIndexOf( "/" )), 127 | repUrls = function( css ){ 128 | return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" ); 129 | }, 130 | useMedia = !ql && media, 131 | //vars used in loop 132 | i = 0, 133 | j, fullq, thisq, eachq, eql; 134 | 135 | //if path exists, tack on trailing slash 136 | if( href.length ){ href += "/"; } 137 | 138 | //if no internal queries exist, but media attr does, use that 139 | //note: this currently lacks support for situations where a media attr is specified on a link AND 140 | //its associated stylesheet has internal CSS media queries. 141 | //In those cases, the media attribute will currently be ignored. 142 | if( useMedia ){ 143 | ql = 1; 144 | } 145 | 146 | 147 | for( ; i < ql; i++ ){ 148 | j = 0; 149 | 150 | //media attr 151 | if( useMedia ){ 152 | fullq = media; 153 | rules.push( repUrls( styles ) ); 154 | } 155 | //parse for styles 156 | else{ 157 | fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1; 158 | rules.push( RegExp.$2 && repUrls( RegExp.$2 ) ); 159 | } 160 | 161 | eachq = fullq.split( "," ); 162 | eql = eachq.length; 163 | 164 | for( ; j < eql; j++ ){ 165 | thisq = eachq[ j ]; 166 | mediastyles.push( { 167 | media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all", 168 | rules : rules.length - 1, 169 | hasquery: thisq.indexOf("(") > -1, 170 | minw : thisq.match( /\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ), 171 | maxw : thisq.match( /\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ) 172 | } ); 173 | } 174 | } 175 | 176 | applyMedia(); 177 | }, 178 | 179 | lastCall, 180 | 181 | resizeDefer, 182 | 183 | // returns the value of 1em in pixels 184 | getEmValue = function() { 185 | var ret, 186 | div = doc.createElement('div'), 187 | body = doc.body, 188 | fakeUsed = false; 189 | 190 | div.style.cssText = "position:absolute;font-size:1em;width:1em"; 191 | 192 | if( !body ){ 193 | body = fakeUsed = doc.createElement( "body" ); 194 | body.style.background = "none"; 195 | } 196 | 197 | body.appendChild( div ); 198 | 199 | docElem.insertBefore( body, docElem.firstChild ); 200 | 201 | ret = div.offsetWidth; 202 | 203 | if( fakeUsed ){ 204 | docElem.removeChild( body ); 205 | } 206 | else { 207 | body.removeChild( div ); 208 | } 209 | 210 | //also update eminpx before returning 211 | ret = eminpx = parseFloat(ret); 212 | 213 | return ret; 214 | }, 215 | 216 | //cached container for 1em value, populated the first time it's needed 217 | eminpx, 218 | 219 | //enable/disable styles 220 | applyMedia = function( fromResize ){ 221 | var name = "clientWidth", 222 | docElemProp = docElem[ name ], 223 | currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp, 224 | styleBlocks = {}, 225 | lastLink = links[ links.length-1 ], 226 | now = (new Date()).getTime(); 227 | 228 | //throttle resize calls 229 | if( fromResize && lastCall && now - lastCall < resizeThrottle ){ 230 | clearTimeout( resizeDefer ); 231 | resizeDefer = setTimeout( applyMedia, resizeThrottle ); 232 | return; 233 | } 234 | else { 235 | lastCall = now; 236 | } 237 | 238 | for( var i in mediastyles ){ 239 | var thisstyle = mediastyles[ i ], 240 | min = thisstyle.minw, 241 | max = thisstyle.maxw, 242 | minnull = min === null, 243 | maxnull = max === null, 244 | em = "em"; 245 | 246 | if( !!min ){ 247 | min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); 248 | } 249 | if( !!max ){ 250 | max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); 251 | } 252 | 253 | // if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true 254 | if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){ 255 | if( !styleBlocks[ thisstyle.media ] ){ 256 | styleBlocks[ thisstyle.media ] = []; 257 | } 258 | styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] ); 259 | } 260 | } 261 | 262 | //remove any existing respond style element(s) 263 | for( var i in appendedEls ){ 264 | if( appendedEls[ i ] && appendedEls[ i ].parentNode === head ){ 265 | head.removeChild( appendedEls[ i ] ); 266 | } 267 | } 268 | 269 | //inject active styles, grouped by media type 270 | for( var i in styleBlocks ){ 271 | var ss = doc.createElement( "style" ), 272 | css = styleBlocks[ i ].join( "\n" ); 273 | 274 | ss.type = "text/css"; 275 | ss.media = i; 276 | 277 | //originally, ss was appended to a documentFragment and sheets were appended in bulk. 278 | //this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one! 279 | head.insertBefore( ss, lastLink.nextSibling ); 280 | 281 | if ( ss.styleSheet ){ 282 | ss.styleSheet.cssText = css; 283 | } 284 | else { 285 | ss.appendChild( doc.createTextNode( css ) ); 286 | } 287 | 288 | //push to appendedEls to track for later removal 289 | appendedEls.push( ss ); 290 | } 291 | }, 292 | //tweaked Ajax functions from Quirksmode 293 | ajax = function( url, callback ) { 294 | var req = xmlHttp(); 295 | if (!req){ 296 | return; 297 | } 298 | req.open( "GET", url, true ); 299 | req.onreadystatechange = function () { 300 | if ( req.readyState != 4 || req.status != 200 && req.status != 304 ){ 301 | return; 302 | } 303 | callback( req.responseText ); 304 | } 305 | if ( req.readyState == 4 ){ 306 | return; 307 | } 308 | req.send( null ); 309 | }, 310 | //define ajax obj 311 | xmlHttp = (function() { 312 | var xmlhttpmethod = false; 313 | try { 314 | xmlhttpmethod = new XMLHttpRequest(); 315 | } 316 | catch( e ){ 317 | xmlhttpmethod = new ActiveXObject( "Microsoft.XMLHTTP" ); 318 | } 319 | return function(){ 320 | return xmlhttpmethod; 321 | }; 322 | })(); 323 | 324 | //translate CSS 325 | ripCSS(); 326 | 327 | //expose update for re-running respond later on 328 | respond.update = ripCSS; 329 | 330 | //adjust on resize 331 | function callMedia(){ 332 | applyMedia( true ); 333 | } 334 | if( win.addEventListener ){ 335 | win.addEventListener( "resize", callMedia, false ); 336 | } 337 | else if( win.attachEvent ){ 338 | win.attachEvent( "onresize", callMedia ); 339 | } 340 | })(this); 341 | -------------------------------------------------------------------------------- /ChatApplication/Scripts/respond.min.js: -------------------------------------------------------------------------------- 1 | /* NUGET: BEGIN LICENSE TEXT 2 | * 3 | * Microsoft grants you the right to use these script files for the sole 4 | * purpose of either: (i) interacting through your browser with the Microsoft 5 | * website or online service, subject to the applicable licensing or use 6 | * terms; or (ii) using the files as included with a Microsoft product subject 7 | * to that product's license terms. Microsoft reserves all other rights to the 8 | * files not expressly granted by Microsoft, whether by implication, estoppel 9 | * or otherwise. Insofar as a script file is dual licensed under GPL, 10 | * Microsoft neither took the code under GPL nor distributes it thereunder but 11 | * under the terms set out in this paragraph. All notices and licenses 12 | * below are for informational purposes only. 13 | * 14 | * NUGET: END LICENSE TEXT */ 15 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */ 16 | /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */ 17 | window.matchMedia=window.matchMedia||(function(e,f){var c,a=e.documentElement,b=a.firstElementChild||a.firstChild,d=e.createElement("body"),g=e.createElement("div");g.id="mq-test-1";g.style.cssText="position:absolute;top:-100em";d.style.background="none";d.appendChild(g);return function(h){g.innerHTML='­';a.insertBefore(d,b);c=g.offsetWidth==42;a.removeChild(d);return{matches:c,media:h}}})(document); 18 | 19 | /*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 20 | (function(e){e.respond={};respond.update=function(){};respond.mediaQueriesSupported=e.matchMedia&&e.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var w=e.document,s=w.documentElement,i=[],k=[],q=[],o={},h=30,f=w.getElementsByTagName("head")[0]||s,g=w.getElementsByTagName("base")[0],b=f.getElementsByTagName("link"),d=[],a=function(){var D=b,y=D.length,B=0,A,z,C,x;for(;B-1,minw:F.match(/\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:F.match(/\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}}j()},l,r,v=function(){var z,A=w.createElement("div"),x=w.body,y=false;A.style.cssText="position:absolute;font-size:1em;width:1em";if(!x){x=y=w.createElement("body");x.style.background="none"}x.appendChild(A);s.insertBefore(x,s.firstChild);z=A.offsetWidth;if(y){s.removeChild(x)}else{x.removeChild(A)}z=p=parseFloat(z);return z},p,j=function(I){var x="clientWidth",B=s[x],H=w.compatMode==="CSS1Compat"&&B||w.body[x]||B,D={},G=b[b.length-1],z=(new Date()).getTime();if(I&&l&&z-l-1?(p||v()):1)}if(!!J){J=parseFloat(J)*(J.indexOf(y)>-1?(p||v()):1)}if(!K.hasquery||(!A||!L)&&(A||H>=C)&&(L||H<=J)){if(!D[K.media]){D[K.media]=[]}D[K.media].push(k[K.rules])}}for(var E in q){if(q[E]&&q[E].parentNode===f){f.removeChild(q[E])}}for(var E in D){var M=w.createElement("style"),F=D[E].join("\n");M.type="text/css";M.media=E;f.insertBefore(M,G.nextSibling);if(M.styleSheet){M.styleSheet.cssText=F}else{M.appendChild(w.createTextNode(F))}q.push(M)}},n=function(x,z){var y=c();if(!y){return}y.open("GET",x,true);y.onreadystatechange=function(){if(y.readyState!=4||y.status!=200&&y.status!=304){return}z(y.responseText)};if(y.readyState==4){return}y.send(null)},c=(function(){var x=false;try{x=new XMLHttpRequest()}catch(y){x=new ActiveXObject("Microsoft.XMLHTTP")}return function(){return x}})();a();respond.update=a;function t(){j(true)}if(e.addEventListener){e.addEventListener("resize",t,false)}else{if(e.attachEvent){e.attachEvent("onresize",t)}}})(this); -------------------------------------------------------------------------------- /ChatApplication/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Owin; 2 | using Owin; 3 | 4 | [assembly: OwinStartupAttribute(typeof(ChatApplication.Startup))] 5 | namespace ChatApplication 6 | { 7 | public partial class Startup 8 | { 9 | public void Configuration(IAppBuilder app) 10 | { 11 | ConfigureAuth(app); 12 | 13 | app.MapSignalR(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ChatApplication/Views/Account/ConfirmEmail.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Confirm Email"; 3 | } 4 | 5 |

    @ViewBag.Title.

    6 |
    7 |

    8 | Thank you for confirming your email. Please @Html.ActionLink("Click here to Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" }) 9 |

    10 |
    11 | -------------------------------------------------------------------------------- /ChatApplication/Views/Account/ExternalLoginConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @model ChatApplication.Models.ExternalLoginConfirmationViewModel 2 | @{ 3 | ViewBag.Title = "Register"; 4 | } 5 |

    @ViewBag.Title.

    6 |

    Associate your @ViewBag.LoginProvider account.

    7 | 8 | @using (Html.BeginForm("ExternalLoginConfirmation", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 | 12 |

    Association Form

    13 |
    14 | @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 15 |

    16 | You've successfully authenticated with @ViewBag.LoginProvider. 17 | Please enter a user name for this site below and click the Register button to finish 18 | logging in. 19 |

    20 |
    21 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 22 |
    23 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 24 | @Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" }) 25 |
    26 |
    27 |
    28 |
    29 | 30 |
    31 |
    32 | } 33 | 34 | @section Scripts { 35 | @Scripts.Render("~/bundles/jqueryval") 36 | } 37 | -------------------------------------------------------------------------------- /ChatApplication/Views/Account/ExternalLoginFailure.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Login Failure"; 3 | } 4 | 5 |
    6 |

    @ViewBag.Title.

    7 |

    Unsuccessful login with service.

    8 |
    9 | -------------------------------------------------------------------------------- /ChatApplication/Views/Account/ForgotPassword.cshtml: -------------------------------------------------------------------------------- 1 | @model ChatApplication.Models.ForgotPasswordViewModel 2 | @{ 3 | ViewBag.Title = "Forgot your password?"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("ForgotPassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

    Enter your email.

    12 |
    13 | @Html.ValidationSummary("", new { @class = "text-danger" }) 14 |
    15 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 16 |
    17 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 18 |
    19 |
    20 |
    21 |
    22 | 23 |
    24 |
    25 | } 26 | 27 | @section Scripts { 28 | @Scripts.Render("~/bundles/jqueryval") 29 | } 30 | -------------------------------------------------------------------------------- /ChatApplication/Views/Account/ForgotPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Forgot Password Confirmation"; 3 | } 4 | 5 |
    6 |

    @ViewBag.Title.

    7 |
    8 |
    9 |

    10 | Please check your email to reset your password. 11 |

    12 |
    13 | 14 | -------------------------------------------------------------------------------- /ChatApplication/Views/Account/Login.cshtml: -------------------------------------------------------------------------------- 1 | @using ChatApplication.Models 2 | @model LoginViewModel 3 | @{ 4 | ViewBag.Title = "Log in"; 5 | } 6 | 7 |

    @ViewBag.Title.

    8 |
    9 |
    10 |
    11 | @using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 12 | { 13 | @Html.AntiForgeryToken() 14 |

    Use a local account to log in.

    15 |
    16 | @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 17 |
    18 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 19 |
    20 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 21 | @Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" }) 22 |
    23 |
    24 |
    25 | @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" }) 26 |
    27 | @Html.PasswordFor(m => m.Password, new { @class = "form-control" }) 28 | @Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" }) 29 |
    30 |
    31 |
    32 |
    33 |
    34 | @Html.CheckBoxFor(m => m.RememberMe) 35 | @Html.LabelFor(m => m.RememberMe) 36 |
    37 |
    38 |
    39 |
    40 |
    41 | 42 |
    43 |
    44 |

    45 | @Html.ActionLink("Register as a new user", "Register") 46 |

    47 | @* Enable this once you have account confirmation enabled for password reset functionality 48 |

    49 | @Html.ActionLink("Forgot your password?", "ForgotPassword") 50 |

    *@ 51 | } 52 |
    53 |
    54 |
    55 |
    56 | @Html.Partial("_ExternalLoginsListPartial", new ExternalLoginListViewModel { ReturnUrl = ViewBag.ReturnUrl }) 57 |
    58 |
    59 |
    60 | 61 | @section Scripts { 62 | @Scripts.Render("~/bundles/jqueryval") 63 | } -------------------------------------------------------------------------------- /ChatApplication/Views/Account/Register.cshtml: -------------------------------------------------------------------------------- 1 | @model ChatApplication.Models.RegisterViewModel 2 | @{ 3 | ViewBag.Title = "Register"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

    Create a new account.

    12 |
    13 | @Html.ValidationSummary("", new { @class = "text-danger" }) 14 |
    15 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 16 |
    17 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 18 |
    19 |
    20 |
    21 | @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" }) 22 |
    23 | @Html.PasswordFor(m => m.Password, new { @class = "form-control" }) 24 |
    25 |
    26 |
    27 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 28 |
    29 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 30 |
    31 |
    32 |
    33 |
    34 | 35 |
    36 |
    37 | } 38 | 39 | @section Scripts { 40 | @Scripts.Render("~/bundles/jqueryval") 41 | } 42 | -------------------------------------------------------------------------------- /ChatApplication/Views/Account/ResetPassword.cshtml: -------------------------------------------------------------------------------- 1 | @model ChatApplication.Models.ResetPasswordViewModel 2 | @{ 3 | ViewBag.Title = "Reset password"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("ResetPassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

    Reset your password.

    12 |
    13 | @Html.ValidationSummary("", new { @class = "text-danger" }) 14 | @Html.HiddenFor(model => model.Code) 15 |
    16 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 17 |
    18 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 19 |
    20 |
    21 |
    22 | @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" }) 23 |
    24 | @Html.PasswordFor(m => m.Password, new { @class = "form-control" }) 25 |
    26 |
    27 |
    28 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 29 |
    30 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 31 |
    32 |
    33 |
    34 |
    35 | 36 |
    37 |
    38 | } 39 | 40 | @section Scripts { 41 | @Scripts.Render("~/bundles/jqueryval") 42 | } 43 | -------------------------------------------------------------------------------- /ChatApplication/Views/Account/ResetPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Reset password confirmation"; 3 | } 4 | 5 |
    6 |

    @ViewBag.Title.

    7 |
    8 |
    9 |

    10 | Your password has been reset. Please @Html.ActionLink("click here to log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" }) 11 |

    12 |
    13 | -------------------------------------------------------------------------------- /ChatApplication/Views/Account/SendCode.cshtml: -------------------------------------------------------------------------------- 1 | @model ChatApplication.Models.SendCodeViewModel 2 | @{ 3 | ViewBag.Title = "Send"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("SendCode", "Account", new { ReturnUrl = Model.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) { 9 | @Html.AntiForgeryToken() 10 | @Html.Hidden("rememberMe", @Model.RememberMe) 11 |

    Send verification code

    12 |
    13 |
    14 |
    15 | Select Two-Factor Authentication Provider: 16 | @Html.DropDownListFor(model => model.SelectedProvider, Model.Providers) 17 | 18 |
    19 |
    20 | } 21 | 22 | @section Scripts { 23 | @Scripts.Render("~/bundles/jqueryval") 24 | } 25 | -------------------------------------------------------------------------------- /ChatApplication/Views/Account/VerifyCode.cshtml: -------------------------------------------------------------------------------- 1 | @model ChatApplication.Models.VerifyCodeViewModel 2 | @{ 3 | ViewBag.Title = "Verify"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("VerifyCode", "Account", new { ReturnUrl = Model.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) { 9 | @Html.AntiForgeryToken() 10 | @Html.Hidden("provider", @Model.Provider) 11 | @Html.Hidden("rememberMe", @Model.RememberMe) 12 |

    Enter verification code

    13 |
    14 | @Html.ValidationSummary("", new { @class = "text-danger" }) 15 |
    16 | @Html.LabelFor(m => m.Code, new { @class = "col-md-2 control-label" }) 17 |
    18 | @Html.TextBoxFor(m => m.Code, new { @class = "form-control" }) 19 |
    20 |
    21 |
    22 |
    23 |
    24 | @Html.CheckBoxFor(m => m.RememberBrowser) 25 | @Html.LabelFor(m => m.RememberBrowser) 26 |
    27 |
    28 |
    29 |
    30 |
    31 | 32 |
    33 |
    34 | } 35 | 36 | @section Scripts { 37 | @Scripts.Render("~/bundles/jqueryval") 38 | } 39 | -------------------------------------------------------------------------------- /ChatApplication/Views/Account/_ExternalLoginsListPartial.cshtml: -------------------------------------------------------------------------------- 1 | @model ChatApplication.Models.ExternalLoginListViewModel 2 | @using Microsoft.Owin.Security 3 | 4 |

    Use another service to log in.

    5 |
    6 | @{ 7 | var loginProviders = Context.GetOwinContext().Authentication.GetExternalAuthenticationTypes(); 8 | if (loginProviders.Count() == 0) { 9 |
    10 |

    11 | There are no external authentication services configured. See this article 12 | for details on setting up this ASP.NET application to support logging in via external services. 13 |

    14 |
    15 | } 16 | else { 17 | using (Html.BeginForm("ExternalLogin", "Account", new { ReturnUrl = Model.ReturnUrl })) { 18 | @Html.AntiForgeryToken() 19 |
    20 |

    21 | @foreach (AuthenticationDescription p in loginProviders) { 22 | 23 | } 24 |

    25 |
    26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ChatApplication/Views/Home/About.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "About"; 3 | } 4 |

    @ViewBag.Title.

    5 |

    @ViewBag.Message

    6 | 7 |

    Use this area to provide additional information.

    8 | -------------------------------------------------------------------------------- /ChatApplication/Views/Home/Chat.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Chat"; 3 | Layout = null; 4 | } 5 | 6 |

    STUDYXNET Chat - Signal R

    7 | 8 | 16 | 17 | 18 |
    19 | 20 | 21 | 22 |
      23 |
      24 | 25 | 26 | @* 27 | 28 | *@ 29 | 30 | 31 | 32 | 33 | 34 | 35 | 75 | -------------------------------------------------------------------------------- /ChatApplication/Views/Home/Contact.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Contact"; 3 | } 4 |

      @ViewBag.Title.

      5 |

      @ViewBag.Message

      6 | 7 |
      8 | One Microsoft Way
      9 | Redmond, WA 98052-6399
      10 | P: 11 | 425.555.0100 12 |
      13 | 14 |
      15 | Support: Support@example.com
      16 | Marketing: Marketing@example.com 17 |
      -------------------------------------------------------------------------------- /ChatApplication/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Home Page"; 3 | } 4 | 5 |
      6 |

      ASP.NET

      7 |

      ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.

      8 |

      Learn more »

      9 |
      10 | 11 |
      12 |
      13 |

      Getting started

      14 |

      15 | ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that 16 | enables a clean separation of concerns and gives you full control over markup 17 | for enjoyable, agile development. 18 |

      19 |

      Learn more »

      20 |
      21 |
      22 |

      Get more libraries

      23 |

      NuGet is a free Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects.

      24 |

      Learn more »

      25 |
      26 |
      27 |

      Web Hosting

      28 |

      You can easily find a web hosting company that offers the right mix of features and price for your applications.

      29 |

      Learn more »

      30 |
      31 |
      -------------------------------------------------------------------------------- /ChatApplication/Views/Manage/AddPhoneNumber.cshtml: -------------------------------------------------------------------------------- 1 | @model ChatApplication.Models.AddPhoneNumberViewModel 2 | @{ 3 | ViewBag.Title = "Phone Number"; 4 | } 5 | 6 |

      @ViewBag.Title.

      7 | 8 | @using (Html.BeginForm("AddPhoneNumber", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

      Add a phone number

      12 |
      13 | @Html.ValidationSummary("", new { @class = "text-danger" }) 14 |
      15 | @Html.LabelFor(m => m.Number, new { @class = "col-md-2 control-label" }) 16 |
      17 | @Html.TextBoxFor(m => m.Number, new { @class = "form-control" }) 18 |
      19 |
      20 |
      21 |
      22 | 23 |
      24 |
      25 | } 26 | 27 | @section Scripts { 28 | @Scripts.Render("~/bundles/jqueryval") 29 | } 30 | -------------------------------------------------------------------------------- /ChatApplication/Views/Manage/ChangePassword.cshtml: -------------------------------------------------------------------------------- 1 | @model ChatApplication.Models.ChangePasswordViewModel 2 | @{ 3 | ViewBag.Title = "Change Password"; 4 | } 5 | 6 |

      @ViewBag.Title.

      7 | 8 | @using (Html.BeginForm("ChangePassword", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

      Change Password Form

      12 |
      13 | @Html.ValidationSummary("", new { @class = "text-danger" }) 14 |
      15 | @Html.LabelFor(m => m.OldPassword, new { @class = "col-md-2 control-label" }) 16 |
      17 | @Html.PasswordFor(m => m.OldPassword, new { @class = "form-control" }) 18 |
      19 |
      20 |
      21 | @Html.LabelFor(m => m.NewPassword, new { @class = "col-md-2 control-label" }) 22 |
      23 | @Html.PasswordFor(m => m.NewPassword, new { @class = "form-control" }) 24 |
      25 |
      26 |
      27 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 28 |
      29 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 30 |
      31 |
      32 |
      33 |
      34 | 35 |
      36 |
      37 | } 38 | @section Scripts { 39 | @Scripts.Render("~/bundles/jqueryval") 40 | } -------------------------------------------------------------------------------- /ChatApplication/Views/Manage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model ChatApplication.Models.IndexViewModel 2 | @{ 3 | ViewBag.Title = "Manage"; 4 | } 5 | 6 |

      @ViewBag.Title.

      7 | 8 |

      @ViewBag.StatusMessage

      9 |
      10 |

      Change your account settings

      11 |
      12 |
      13 |
      Password:
      14 |
      15 | [ 16 | @if (Model.HasPassword) 17 | { 18 | @Html.ActionLink("Change your password", "ChangePassword") 19 | } 20 | else 21 | { 22 | @Html.ActionLink("Create", "SetPassword") 23 | } 24 | ] 25 |
      26 |
      External Logins:
      27 |
      28 | @Model.Logins.Count [ 29 | @Html.ActionLink("Manage", "ManageLogins") ] 30 |
      31 | @* 32 | Phone Numbers can used as a second factor of verification in a two-factor authentication system. 33 | 34 | See this article 35 | for details on setting up this ASP.NET application to support two-factor authentication using SMS. 36 | 37 | Uncomment the following block after you have set up two-factor authentication 38 | *@ 39 | @* 40 |
      Phone Number:
      41 |
      42 | @(Model.PhoneNumber ?? "None") [ 43 | @if (Model.PhoneNumber != null) 44 | { 45 | @Html.ActionLink("Change", "AddPhoneNumber") 46 | @:  |  47 | @Html.ActionLink("Remove", "RemovePhoneNumber") 48 | } 49 | else 50 | { 51 | @Html.ActionLink("Add", "AddPhoneNumber") 52 | } 53 | ] 54 |
      55 | *@ 56 |
      Two-Factor Authentication:
      57 |
      58 |

      59 | There are no two-factor authentication providers configured. See this article 60 | for details on setting up this ASP.NET application to support two-factor authentication. 61 |

      62 | @*@if (Model.TwoFactor) 63 | { 64 | using (Html.BeginForm("DisableTwoFactorAuthentication", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 65 | { 66 | @Html.AntiForgeryToken() 67 | Enabled 68 | 69 | 70 | } 71 | } 72 | else 73 | { 74 | using (Html.BeginForm("EnableTwoFactorAuthentication", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 75 | { 76 | @Html.AntiForgeryToken() 77 | Disabled 78 | 79 | 80 | } 81 | }*@ 82 |
      83 |
      84 |
      85 | -------------------------------------------------------------------------------- /ChatApplication/Views/Manage/ManageLogins.cshtml: -------------------------------------------------------------------------------- 1 | @model ChatApplication.Models.ManageLoginsViewModel 2 | @using Microsoft.Owin.Security 3 | @{ 4 | ViewBag.Title = "Manage your external logins"; 5 | } 6 | 7 |

      @ViewBag.Title.

      8 | 9 |

      @ViewBag.StatusMessage

      10 | @{ 11 | var loginProviders = Context.GetOwinContext().Authentication.GetExternalAuthenticationTypes(); 12 | if (loginProviders.Count() == 0) { 13 |
      14 |

      15 | There are no external authentication services configured. See this article 16 | for details on setting up this ASP.NET application to support logging in via external services. 17 |

      18 |
      19 | } 20 | else 21 | { 22 | if (Model.CurrentLogins.Count > 0) 23 | { 24 |

      Registered Logins

      25 | 26 | 27 | @foreach (var account in Model.CurrentLogins) 28 | { 29 | 30 | 31 | 49 | 50 | } 51 | 52 |
      @account.LoginProvider 32 | @if (ViewBag.ShowRemoveButton) 33 | { 34 | using (Html.BeginForm("RemoveLogin", "Manage")) 35 | { 36 | @Html.AntiForgeryToken() 37 |
      38 | @Html.Hidden("loginProvider", account.LoginProvider) 39 | @Html.Hidden("providerKey", account.ProviderKey) 40 | 41 |
      42 | } 43 | } 44 | else 45 | { 46 | @:   47 | } 48 |
      53 | } 54 | if (Model.OtherLogins.Count > 0) 55 | { 56 | using (Html.BeginForm("LinkLogin", "Manage")) 57 | { 58 | @Html.AntiForgeryToken() 59 |
      60 |

      61 | @foreach (AuthenticationDescription p in Model.OtherLogins) 62 | { 63 | 64 | } 65 |

      66 |
      67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /ChatApplication/Views/Manage/SetPassword.cshtml: -------------------------------------------------------------------------------- 1 | @model ChatApplication.Models.SetPasswordViewModel 2 | @{ 3 | ViewBag.Title = "Create Password"; 4 | } 5 | 6 |

      @ViewBag.Title.

      7 |

      8 | You do not have a local username/password for this site. Add a local 9 | account so you can log in without an external login. 10 |

      11 | 12 | @using (Html.BeginForm("SetPassword", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 13 | { 14 | @Html.AntiForgeryToken() 15 | 16 |

      Create Local Login

      17 |
      18 | @Html.ValidationSummary("", new { @class = "text-danger" }) 19 |
      20 | @Html.LabelFor(m => m.NewPassword, new { @class = "col-md-2 control-label" }) 21 |
      22 | @Html.PasswordFor(m => m.NewPassword, new { @class = "form-control" }) 23 |
      24 |
      25 |
      26 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 27 |
      28 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 29 |
      30 |
      31 |
      32 |
      33 | 34 |
      35 |
      36 | } 37 | @section Scripts { 38 | @Scripts.Render("~/bundles/jqueryval") 39 | } -------------------------------------------------------------------------------- /ChatApplication/Views/Manage/VerifyPhoneNumber.cshtml: -------------------------------------------------------------------------------- 1 | @model ChatApplication.Models.VerifyPhoneNumberViewModel 2 | @{ 3 | ViewBag.Title = "Verify Phone Number"; 4 | } 5 | 6 |

      @ViewBag.Title.

      7 | 8 | @using (Html.BeginForm("VerifyPhoneNumber", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 | @Html.Hidden("phoneNumber", @Model.PhoneNumber) 12 |

      Enter verification code

      13 |
      @ViewBag.Status
      14 |
      15 | @Html.ValidationSummary("", new { @class = "text-danger" }) 16 |
      17 | @Html.LabelFor(m => m.Code, new { @class = "col-md-2 control-label" }) 18 |
      19 | @Html.TextBoxFor(m => m.Code, new { @class = "form-control" }) 20 |
      21 |
      22 |
      23 |
      24 | 25 |
      26 |
      27 | } 28 | 29 | @section Scripts { 30 | @Scripts.Render("~/bundles/jqueryval") 31 | } 32 | -------------------------------------------------------------------------------- /ChatApplication/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model System.Web.Mvc.HandleErrorInfo 2 | 3 | @{ 4 | ViewBag.Title = "Error"; 5 | } 6 | 7 |

      Error.

      8 |

      An error occurred while processing your request.

      9 | 10 | -------------------------------------------------------------------------------- /ChatApplication/Views/Shared/Lockout.cshtml: -------------------------------------------------------------------------------- 1 | @model System.Web.Mvc.HandleErrorInfo 2 | 3 | @{ 4 | ViewBag.Title = "Locked Out"; 5 | } 6 | 7 |
      8 |

      Locked out.

      9 |

      This account has been locked out, please try again later.

      10 |
      11 | -------------------------------------------------------------------------------- /ChatApplication/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewBag.Title - My ASP.NET Application 7 | @Styles.Render("~/Content/css") 8 | @Scripts.Render("~/bundles/modernizr") 9 | 10 | 11 | 12 | 32 |
      33 | @RenderBody() 34 |
      35 |
      36 |

      © @DateTime.Now.Year - My ASP.NET Application

      37 |
      38 |
      39 | 40 | @Scripts.Render("~/bundles/jquery") 41 | @Scripts.Render("~/bundles/bootstrap") 42 | @RenderSection("scripts", required: false) 43 | 44 | 45 | -------------------------------------------------------------------------------- /ChatApplication/Views/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNet.Identity 2 | @if (Request.IsAuthenticated) 3 | { 4 | using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" })) 5 | { 6 | @Html.AntiForgeryToken() 7 | 8 | 14 | } 15 | } 16 | else 17 | { 18 | 22 | } 23 | -------------------------------------------------------------------------------- /ChatApplication/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
      7 |
      8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /ChatApplication/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /ChatApplication/Web.Debug.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /ChatApplication/Web.Release.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /ChatApplication/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 |
      10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /ChatApplication/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IncredibleWeb/SignalR-Server/205404394a90c5eaba2597532dca4f6bed254ebb/ChatApplication/favicon.ico -------------------------------------------------------------------------------- /ChatApplication/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IncredibleWeb/SignalR-Server/205404394a90c5eaba2597532dca4f6bed254ebb/ChatApplication/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /ChatApplication/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IncredibleWeb/SignalR-Server/205404394a90c5eaba2597532dca4f6bed254ebb/ChatApplication/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /ChatApplication/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IncredibleWeb/SignalR-Server/205404394a90c5eaba2597532dca4f6bed254ebb/ChatApplication/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /ChatApplication/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SignalR-Server 2 | A simple SignalR server and javascript client which can be used to demonstrate the capabilities of SignalR in the field of real-time applications. 3 | This particular SignalR client was deployed to an Azure App and utilized through a web and multiple Xamarin Forms Chat applications. 4 | 5 | Using a central SignalR sever, all the clients can reference the hub and push messages to it through the designated URL. The clients can then listen for incoming messages on the hub. 6 | 7 | The Web client can be run by deploying the web app and accessing /chat. 8 | 9 | The Mobile Applications are available through: https://github.com/IncredibleWeb/Xamarin-Forms-Chat-Client 10 | --------------------------------------------------------------------------------