Trying to apply some specific bootstrap layouts turned into strange results. For example I simple wanted to horizontally centering an input box, or one of these special composite bootstrap controls combining an Input box and a button left or right side, within a md-12 row and got a layout result that aligns the Input box left side and the button right side. The Level of strangeness depends on the current size of the viewport e.g. mobile phone vs. desktop monitor.
To resolve this issue I did a lot of stackoverflow but without any result.
I ended up with a simple approach: Remove the site.css file from spa template completely and andapt the bündle.config then.
This "tweak" works for me and did not result in any new layout issues ;-): The bootstrap Composite controls are now aligned/centered as expected.
This private blog solely depicts (IMHO) the "Visual Studio 2013 SPA template" that is focussed on Single Page Application web development using JavaScript, JQuery, knockout.js on the client side and WEB.API in conjunction with OWIN cookie authentication middleware on the server side. (All diagrams / images by author, all Information for illustration use only). Unfortunately the author did dissecting with a DE localized VS2013 Ultimate evaluation edition. I'm so sorry about that !
Freitag, 17. Oktober 2014
Donnerstag, 16. Oktober 2014
ASP.NET MVC5: Organizing large solutions with areas
A working example by code snob:
http://codesnob.wordpress.com/2014/03/06/mvc-area-in-an-external-assembly/
and the source code (vs solution):
https://github.com/drydenmaker/PMMA-MVC
Advice:
Perhaps if you are encountering an jquery error on executing too then please check the _Layout.cshtml file. Scroll to bottom of file and look for this stuff:
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
If the line @Scripts.Render("~/bundles/jquery"
) is missing then please insert this code snippet right before
@Scripts.Render("~/bundles/bootstrap")
Then it will work properly !
Thanks.
http://codesnob.wordpress.com/2014/03/06/mvc-area-in-an-external-assembly/
and the source code (vs solution):
https://github.com/drydenmaker/PMMA-MVC
Advice:
Perhaps if you are encountering an jquery error on executing too then please check the _Layout.cshtml file. Scroll to bottom of file and look for this stuff:
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
If the line @Scripts.Render("~/bundles/jquery"
) is missing then please insert this code snippet right before
@Scripts.Render("~/bundles/bootstrap")
Then it will work properly !
Thanks.
Donnerstag, 6. März 2014
Mittwoch, 5. März 2014
Quote: Script Loader RequireJS and curl.js
Addy Osmani:
"There are a number of great loaders for handling module loading in the AMD and CommonJS formats, but my personal preferences are RequireJS and curl.js. Complete tutorials on these tools are outside the scope of this book, but I can recommend reading John Hann's article about curl.js and James Burke's RequireJS API documentation for more."
http://msdn.microsoft.com/en-us/magazine/hh227261.aspx
Source: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modularjavascript
"There are a number of great loaders for handling module loading in the AMD and CommonJS formats, but my personal preferences are RequireJS and curl.js. Complete tutorials on these tools are outside the scope of this book, but I can recommend reading John Hann's article about curl.js and James Burke's RequireJS API documentation for more."
http://msdn.microsoft.com/en-us/magazine/hh227261.aspx
Source: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modularjavascript
Quote: Developers fall back on variations of the module or object literal
Addy Osmani:
"Unlike some more traditional programming languages however, the current iteration of JavaScript (ECMA-262) doesn't provide developers with the means to import such modules of code in a clean, organized manner. It's one of the concerns with specifications that haven't required great thought until more recent years where the need for more organized JavaScript applications became apparent.
Instead, developers at present are left to fall back on variations of the module or object literal patterns, which we covered earlier in the book. With many of these, module scripts are strung together in the DOM with namespaces being described by a single global object where it's still possible to incur naming collisions in our architecture. There's also no clean way to handle dependency management without some manual effort or third party tools."
Quote: backbone.js vs. knockout.js
Addy Osmani:
"To conclude, I personally find KnockoutJS more suitable for smaller applications whilst Backbone’s feature set really shines when building anything non-trivial. That said, many developers have used both frameworks to write applications of varying complexity and I recommend trying out both at a smaller scale before making a decision on which might work best for your Project."
Source: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#detailmvvm
"To conclude, I personally find KnockoutJS more suitable for smaller applications whilst Backbone’s feature set really shines when building anything non-trivial. That said, many developers have used both frameworks to write applications of varying complexity and I recommend trying out both at a smaller scale before making a decision on which might work best for your Project."
Source: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#detailmvvm
Montag, 3. März 2014
Template JS: No .prototype - signature found in VS2013 SPA template
A check against the so called constructor pattern results in no ".prototype" hits concerning the VS2013 SPA template JS codebase.
Samstag, 1. März 2014
WebDeploy: Successfully registered and logged in a new user using VS2013 SPA template with local IIS 7.x
1. Try a Login with user: demo and password: demodemo
2. Register with user:demo and password: demodemo
3. Displaying the Home welcome page after logged in successfully
4. Showing the data Schema with some user data that was entered automatically during registering process
WebDeploy: Now working with local IIS 7.x on root deployment
Actually there still exists a Problem - for me - to get a proper solution working with a URL that directs to a IIS subfolder. This problem is currently addressed solely to forementioned "UNKNOWN ERROR OCCURED" error, when a user sends a request to http://localhost/VS2013SPATemplateOriginal.
I did a simple workaround then. Deploying the whole stuff to the IIS root folder "Default Websites" the VS2013 SPA template works properly. A user sends a request by entering http://localhost and the stuff is up and running as expected.
Therefore I will skip further investigations and proceed examining the VS2013 SPA template en detail from now.
Working steps for web deployment by using VS2013 Publishing functionality:
1. Publishing Connection
2. Publishing settings
...and the Folder structure within IIS 7.x
...and the folder structure on disk by Windows Explorer
...and the output by Visual Studio during publishing that ends successfully:
1>------ Erstellen gestartet: Projekt: VS2013SPATemplateDemo, Konfiguration: Release Any CPU ------
1> VS2013SPATemplateDemo -> C:\Daten\Projekte\VS2013\WebApp\VS2013SPATemplateDemo\VS2013SPATemplateDemo\bin\VS2013SPATemplateDemo.dll
2>------ Veröffentlichungsvorgang gestartet: Projekt: VS2013SPATemplateDemo, Konfiguration: Release Any CPU ------
2>"Web.config" wurde mithilfe von "C:\Daten\Projekte\VS2013\WebApp\VS2013SPATemplateDemo\VS2013SPATemplateDemo\Web.Release.config" in "obj\Release\TransformWebConfig\transformed\Web.config" transformiert.
2>Alle Dateien werden in das unten genannte temporäre Verzeichnis zum Packen/Veröffentlichen kopiert:
2>obj\Release\AspnetCompileMerge\Source.
2>C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_compiler.exe -v / -p C:\Daten\Projekte\VS2013\WebApp\VS2013SPATemplateDemo\VS2013SPATemplateDemo\obj\Release\AspnetCompileMerge\Source -u C:\Daten\Projekte\VS2013\WebApp\VS2013SPATemplateDemo\VS2013SPATemplateDemo\obj\Release\AspnetCompileMerge\TempBuildDir
2>C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\Web\Deploy\Microsoft.Web.Publishing.MSDeploy.Common.targets(55,5): Warnung : Die angegebene DACPAC-Datei ist bereits vorhanden und wird überschrieben.
2>MSDeploy.dbDacFx (MSDeploy.dbDacFx) wird hinzugefügt.
2>Die Datenbank (C:\Daten\Projekte\VS2013\WebApp\VS2013SPATemplateDemo\VS2013SPATemplateDemo\obj\Release\AutoScripts\DefaultConnection_IncrementalSchemaOnly.dacpac) wird hinzugefügt.
2>Die automatische "ConnectionString" hat "obj\Release\AspnetCompileMerge\TempBuildDir\Areas\HelpPage\Views\Web.config" in "obj\Release\CSAutoParameterize\transformed\Areas\HelpPage\Views\Web.config" transformiert.
2>Die automatische "ConnectionString" hat "obj\Release\AspnetCompileMerge\TempBuildDir\Views\Web.config" in "obj\Release\CSAutoParameterize\transformed\Views\Web.config" transformiert.
2>Die automatische "ConnectionString" hat "obj\Release\AspnetCompileMerge\TempBuildDir\Web.config" in "obj\Release\CSAutoParameterize\transformed\Web.config" transformiert.
2>Alle Dateien werden in das unten genannte temporäre Verzeichnis zum Packen/Veröffentlichen kopiert:
2>obj\Release\Package\PackageTmp.
2>sitemanifest (sitemanifest) wird hinzugefügt.
2>Die Datenbank (data source=.\SQLExpress;initial catalog=VS2013SPATemplateDemoOriginalDB;integrated security=True;connect timeout=30) wird hinzugefügt.
2>Die Datei (Default Web Site\bin\App_global.asax.compiled) wird aktualisiert.
2>Die Datei (Default Web Site\bin\App_global.asax.dll) wird aktualisiert.
2>Die Datei (Default Web Site\PrecompiledApp.config) wird aktualisiert.
2>ACLs für den Pfad (Default Web Site) werden hinzugefügt.
2>ACLs für den Pfad (Default Web Site) werden hinzugefügt.
2>Die Veröffentlichung war erfolgreich.
2>Die Website wurde erfolgreich veröffentlicht http://localhost/
========== Erstellen: 1 erfolgreich, 0 fehlerhaft, 0 aktuell, 0 übersprungen ==========
========== Veröffentlichung: 1 erfolgreich, 0 Fehler, 0 übersprungen ==========
UnknownError: Hosting the VS2013 SPA template not in IIS root but subfolder
After deploying the VS2013 SPA template application including performed database schema changes the login resp. register form shows "unknown error occured" or "Unbekannter Fehler".
Because the deployment process was successful I tried then to dissect this issue:
Freitag, 28. Februar 2014
SQLExpress: Grant priviliges to IIS / SQLExpress
SQLServer Express script for registering a specific user and connect it with IIS
Source: http://www.asp.net/mvc/tutorials/deployment/visual-studio-web-deployment/deploying-to-iis
use VS2013SPATemplateDemoOriginalDB
go
IF NOT EXISTS (SELECT name FROM sys.server_principals WHERE name = 'IIS APPPOOL\DefaultAppPool')
BEGIN
CREATE LOGIN [IIS APPPOOL\DefaultAppPool]
FROM WINDOWS WITH DEFAULT_DATABASE=[master],
DEFAULT_LANGUAGE=[us_english]
END
GO
CREATE USER [VS2013SPATemplateDemoOriginalDBUser]
FOR LOGIN [IIS APPPOOL\DefaultAppPool]
GO
EXEC sp_addrolemember 'db_owner', 'VS2013SPATemplateDemoOriginalDBUser'
GO
Source: http://www.asp.net/mvc/tutorials/deployment/visual-studio-web-deployment/deploying-to-iis
use VS2013SPATemplateDemoOriginalDB
go
IF NOT EXISTS (SELECT name FROM sys.server_principals WHERE name = 'IIS APPPOOL\DefaultAppPool')
BEGIN
CREATE LOGIN [IIS APPPOOL\DefaultAppPool]
FROM WINDOWS WITH DEFAULT_DATABASE=[master],
DEFAULT_LANGUAGE=[us_english]
END
GO
CREATE USER [VS2013SPATemplateDemoOriginalDBUser]
FOR LOGIN [IIS APPPOOL\DefaultAppPool]
GO
EXEC sp_addrolemember 'db_owner', 'VS2013SPATemplateDemoOriginalDBUser'
GO
WebDeploy: LocalDB, SQLServer Express, ISS 7.x
After some research I came to conclusion that LocalDB that is per default provided with VisualStudo 2013 "built-in" storage does not work in conjunction with WebDeploy resp. IIS 7.x at all.
The VisualStudio 2013 auto-generated <magiccrypticnaming>.mdf database file is deployed successfully to IIS App_Data Folder without any database settings in the publishing dialog but it seems that is not loadable by the IIS infrastructure solely. I am a naif.
There it is, in black and white:
"LocalDB is not designed to work in IIS, so for your test environment you need to have SQL Server Express installed. If you are using Visual Studio 2010 SQL Server Express is already installed by default. If you are using Visual Studio 2012, you have to install it."
[Tom Dykstra, ASP.NET Web Deployment using Visual Studio: Deploying to Test ]
Otherwise using the database settings within publishing dialog and the deployment fails spitting out:
2>Die Datenbank (data source=(LocalDB)\v11.0;attachdbfilename=C:\inetpub\wwwroot\Demo\App_Data\aspnet-VS2013SPATemplateDemo-20140228031558.mdf;integrated security=True;connect timeout=30) wird hinzugefügt.
2>C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.targets(4255,5): Fehler ERROR_EXCEPTION_WHILE_CREATING_OBJECT: Fehler des Webbereitstellungstasks. (Fehler beim Erstellen des Typs "Microsot.SqlServer.Dac.DacServices". Weitere Informationen unter: http://go.microsoft.com/fwlink/?LinkId=221672#ERROR_EXCEPTION_WHILE_CREATING_OBJECT.)
2>Veröffentlichungsfehler der Bereitstellung.
and additionally comparing to the windows event log:
2>C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.targets(4255,5): Fehler ERROR_EXCEPTION_WHILE_CREATING_OBJECT: Fehler des Webbereitstellungstasks. (Fehler beim Erstellen des Typs "Microsot.SqlServer.Dac.DacServices". Weitere Informationen unter: http://go.microsoft.com/fwlink/?LinkId=221672#ERROR_EXCEPTION_WHILE_CREATING_OBJECT.)
2>Veröffentlichungsfehler der Bereitstellung.
and additionally comparing to the windows event log:
Excursion: Prepareing IIS on WIN7 for use with VS2013 SPA Template
Steps:
1) Install IIS using Windows control Panel
2) Install WebDeploy 3.x for x64 for web deployment via VS2013 "publish" funcionality
Source Scott Guthries blog:
a) run cmd.exe as administrator
b) > net start msdepsvc
c) > cd: “c:\Program Files\IIS\Microsoft Web Deploy V3”
d) > msdeploy –verb:dump –source:appHostConfig,computername=localhost
d) > msdeploy –verb:dump –source:appHostConfig,computername=localhost
Some output comes on cmd window. When there is "red output" check correct spelling of d) in Windows text editor because some quotation marks could appear on scene.
Set the current 4.0 Framework for Application Pool: calling the IIS 7.x Panel: > cmd.exe inetmgr Click on ApplicationPool and set Framework 2.0 to 4.0 If you got an error like: error 500.19 then try this: |
Performing
> cmd aspnet_regiis -i
does the trick for me ;-)
> cmd aspnet_regiis -i
does the trick for me ;-)
Diagram: VS2013 SPA template client side js startup sequence until app.initialize()
It's not visible at a glance how and in what kind of order the client side startup process of the web application comes up exactly when a user wants to start the VS2013 SPA template web application the first time with his user agent resp. browser.
As a basic principle the startup order is controlled by loading order specifications within the html stream that is sent as response from web server to requesting browsers. Once specified by the developer and stored in the corresponding Index.cshtml and subsequent html files e.g. _Login.cshtml, _Home.cshtml etc. the server side rendering process merges all information together in one single html output stream defining amongst others how requesting user agents e.g. IE11 should load relevant script and style libraries.
Under the hood the browser is probably trying to convert the html stream into an internal data structure that resides in browser's working memory. From that point the browser tries to parse and extract information to build a DOM (= Document Object Model) from the HTML markup specification and creates URL collections of loadable JavaScript and CSS Files etc. When the browser states ready with gathering and validating all relevant information the JavaScript Interpreter is invoked and will try to perform executeable code that he has detected within <script>-tags whether inline or by loadable JavaScript - libraries. Some sources stated that browsers perform execution of java script code as they proceed with parsing, that is to say, the parsing process pauses until a inline <script>[JavaScriptCode]</script> Code has been performed. On code return the parsing process proceeds.
Due to performance issues the browser first checks for existing resp. cached JS-files that matches the requested libraries. If there are no cached libraries available the browser exactly tries to load the required files in the specified order and populates step by step the execution stack within the runtime sandbox for the specific web application.
Further sources about Java Script code loading and execution:
http://stackoverflow.com/questions/8996852/load-and-execute-order-of-scripts
http://stackoverflow.com/questions/1795438/load-and-execution-sequence-of-a-web-page?rq=1
http://www.compuware.com/en_us/application-performance-management/products/ajax-free-edition/overview.html
Under the hood the browser is probably trying to convert the html stream into an internal data structure that resides in browser's working memory. From that point the browser tries to parse and extract information to build a DOM (= Document Object Model) from the HTML markup specification and creates URL collections of loadable JavaScript and CSS Files etc. When the browser states ready with gathering and validating all relevant information the JavaScript Interpreter is invoked and will try to perform executeable code that he has detected within <script>-tags whether inline or by loadable JavaScript - libraries. Some sources stated that browsers perform execution of java script code as they proceed with parsing, that is to say, the parsing process pauses until a inline <script>[JavaScriptCode]</script> Code has been performed. On code return the parsing process proceeds.
Due to performance issues the browser first checks for existing resp. cached JS-files that matches the requested libraries. If there are no cached libraries available the browser exactly tries to load the required files in the specified order and populates step by step the execution stack within the runtime sandbox for the specific web application.
Further sources about Java Script code loading and execution:
http://stackoverflow.com/questions/8996852/load-and-execute-order-of-scripts
http://stackoverflow.com/questions/1795438/load-and-execution-sequence-of-a-web-page?rq=1
http://www.compuware.com/en_us/application-performance-management/products/ajax-free-edition/overview.html
Donnerstag, 27. Februar 2014
Diagram: Visual Studio 2013 SPA Template JS Library Declaration And Calling Stack
The calling stack of JavaScript based libraries e.g. jQuery, knockout.js and the template specific "app" js files is depending on the bundle order configuration in BundleConfig.cs and the declaration order within the markup of Index.cshtml.
Please find the attached diagram helpful showing this correlation:
Diagram: knockout.js MVVM in conjunction with ASP.NET Razor View architecture
Understanding the base structure of the knockout.js MVVM system in conjunction with the ASP.NET RazorEngine semi-static views.
MVVM consists of a View, ViewModel and (Data)Model approach where the DataModel is represented by the app.datamodel.js respectively ASP.NET controller/model concept, the ViewModel located in several app.XYZViewModel.js files e.g. app.LoginViewModel.js. The views are realized by razor engine based semi-static html files.
knockout.js MVVM: ko.computed() widely used in template's js files
Manageing subsequent view models e.g. LoginViewModel, HomeViewModel etc. ko.computed() appears on the Scene amongst others.
self.loading = ko.computed(function () { return self.view() === self.Views.Loading; });
// Data self.Views = { Loading: {} // Other views are added dynamically by app.addViewModel(...). }; self.view = ko.observable(self.Views.Loading); self.loading = ko.computed(function () { return self.view() === self.Views.Loading; }); // Other operations self.addViewModel = function (options) { var viewItem = {}, navigator; // Add view to AppViewModel.Views enum (for example, app.Views.Home). self.Views[options.name] = viewItem; // Add binding member to AppViewModel (for example, app.home); self[options.bindingMemberName] = ko.computed(function () { if (self.view() !== viewItem) { return null; } return new options.factory(self, dataModel); }); if (typeof (options.navigatorFactory) !== "undefined") { navigator = options.navigatorFactory(self, dataModel); } else { navigator = function () { self.errors.removeAll(); self.view(viewItem); }; } // Add navigation member to AppViewModel (for example, app.NavigateToHome()); self["navigateTo" + options.name] = navigator; };
knockout.js MVVM: ko.mapping.fromJS - advanced mapping technique not found in template's code
According to the knockout.js tutorial there is an advanced mapping technique available via plugin (knockout.mapping.js) to automatically map JSON based data that is retrieved/sent by AJAX calls to/from knockout viewmodel.
Tutorial: http://knockoutjs.com/documentation/plugins-mapping.html
Download: https://github.com/SteveSanderson/knockout.mapping/tree/master/build/output
This key word was not found yet within the template's code base. Therefore it is not used for now. The mapping is done "manually".
Code snippet from knockout.js tutorial.
The creation of a viewmodel object is done explicitily in template:
Tutorial: http://knockoutjs.com/documentation/plugins-mapping.html
Download: https://github.com/SteveSanderson/knockout.mapping/tree/master/build/output
This key word was not found yet within the template's code base. Therefore it is not used for now. The mapping is done "manually".
Code snippet from knockout.js tutorial.
var viewModel = ko.mapping.fromJS(data);
The creation of a viewmodel object is done explicitily in template:
var app = new AppViewModel(new AppDataModel());
Mittwoch, 26. Februar 2014
knockout.js MVVM: .extend keyword in several SPA template js files found
The implementation of knockout.js MVVM pattern uses the .extend - functionality e.g. in login.viewmodel.js on behalf of the knockout validation plugin. (knockout.validation.js). This plugin script also resides within the Visual Studio SPA template in Folder scripts.
Please refer to: https://github.com/Knockout-Contrib/Knockout-Validation
Afte some CTRL-H search through the template's code it seems that there is no custom ko.extenders - instruction set found. According to the knockout.js tutorial it is possible to create custom extender functionality:
http://knockoutjs.com/documentation/extenders.html
Please refer to: https://github.com/Knockout-Contrib/Knockout-Validation
self.userName = ko.observable("").extend({ required: true });
unction LoginViewModel(app, dataModel) { // Private state var self = this, validationTriggered = ko.observable(false); // Private operations function initialize() { dataModel.getExternalLogins(dataModel.returnUrl, true /* generateState */) .done(function (data) { self.loadingExternalLogin(false); if (typeof (data) === "object") { for (var i = 0; i < data.length; i++) { self.externalLoginProviders.push(new ExternalLoginProviderViewModel(app, data[i])); } } else { self.errors.push("Unbekannter Fehler."); } }).fail(function () { self.loadingExternalLogin(false); self.errors.push("Unbekannter Fehler."); }); } // Data self.userName = ko.observable("").extend({ required: true }); self.password = ko.observable("").extend({ required: true }); self.rememberMe = ko.observable(false); self.externalLoginProviders = ko.observableArray(); self.validationErrors = ko.validation.group([self.userName, self.password]); // Other UI state self.errors = ko.observableArray(); self.loadingExternalLogin = ko.observable(true); self.loggingIn = ko.observable(false); ...
Afte some CTRL-H search through the template's code it seems that there is no custom ko.extenders - instruction set found. According to the knockout.js tutorial it is possible to create custom extender functionality:
http://knockoutjs.com/documentation/extenders.html
knockout.js MVVM: No advanced "subscribe" concept In SPA template js files
When comparing the knockout.js tutorials to the template's js-files there is no "subscribe" key word detected. This is stated as "advanced" by the ko - tutorial.
Sequence-Diagram: User is already logged in and refreshes the browser - (2)
Kind a weird the workflow in debug mode goes when authentication was successfully done and an apparently simply looking instruction "self.navigateToHome is called". The very first sequence of that shows some "magic" infrastructure diagram boxes that are "used" or called through the way down showing the home screen. I have to dissect this apparently knockout.js - based stuff in next Iteration.
Diagram: How UserAgent Interacts with OWIN authentication middleware (Draft)
The interaction between an user agent e.g. ie11 and an OWIN authentication middleware enabled web server depends on the specific Controller that is called by the user agent.
When the OWIN authentication middleware detects an request to a Web.API based Controller that has no cookie resp. a cookie without any bearer token Information it sends back a 401 unauthorized status code to the browser that handles this issue with it's client side code.
If there is a call to an ASP.NET MVC Controller the 401 unauthorized status code is converted into 302 that is sent back to the browser with the URL for the login page.
Please refer to this excellent description published by Microsoft:
Sequence-Diagram: User wants to login with his credentials (username, password)
An "401 unauthorized" HTTP status code is sent back from server to browser, if there is no so called "bearer token" detected by OWIN cookie based middleware when the user tries to connect to the server the first time or did a logoff and refreshes his browser. The user agents client side code then will handle this issue and navigates the user to the login page. Because the authentication is working together with Web.API based AccountController in conjunction with a specific server side configuration there is no classic "302 - Redirect" HTTP status code like in ASP.NET MVC.
Because of the Single-Page-Application (SPA) - architecture a classic redirect to a new page is not appropriate but showing the container on the same page that contains all the login stuff to the user. This is actually controlled by JQuery resp. JavaScript.
At this point the user is enabled to perform a login with his credentials.
Draft: Refactoring app.Initialize() of app.viewmodel.js
When a user does his first attempt to connect to the SPA or refreshes his browser one of the first hookups is the call of self.initialize() of app.viewmodel.js by app.initialize() within _run.js.
Some examination of the initialization code in conjunction with the corresponding AccountController on the server side made it clear to me that it is entirley about local or external authentication and some navigation instructions when the user tried an unauthorized access or is already logged in.
The very first draft tries to extract and encapsulate the authentication code and make the code more readable in terms of workflow processing.
Some examination of the initialization code in conjunction with the corresponding AccountController on the server side made it clear to me that it is entirley about local or external authentication and some navigation instructions when the user tried an unauthorized access or is already logged in.
The very first draft tries to extract and encapsulate the authentication code and make the code more readable in terms of workflow processing.
file: app.viewmodel.js var app = new AppViewModel(new AppDataModel()); function AppViewModel(dataModel) { // Private state var self = this //-- register authentication management var authentication = AppAuthentication; //Navigation behaviour when it comes to access denied authentication function NavigationBehaviourAccessDenied(data) { self.navigateToLogin(); } //Navigation behaviour when it comes to already logged in authentication function NavigationBehaviourAlreadyLoggedIn(data) { if (data.userName) { self.navigateToLoggedIn(data.userName); } else { self.navigateToLogin(); } } authentication.OnAlreadyLoggedIn = NavigationBehaviourAlreadyLoggedIn; authentication.OnAccessDenied = NavigationBehaviourAccessDenied; //-- end of register authentication Management ... self.initialize = function () { Authenticate(); } function Authenticate() { var loginType = sessionStorage["associatingExternalLogin"]; var fragment = AppAuthentication.GetFragment(); if (typeof (loginType) === "undefined") { authentication.AuthenticateLocal(); } if (loginType) { AuthenticateExternal(); } } ... }
file: app.authentication.js //application authentication var AppAuthentication = { OnAlreadyLoggedIn: null, OnAccessDenied: null, AuthenticateLocal: function() { var userInfoUrl = "/api/Account/UserInfo"; var authenticateUser = function (accessToken) { var headers; if (typeof (accessToken) !== "undefined") { headers = { "Authorization": "Bearer " + accessToken }; } else { headers = AppAuthenticationHelper.GetSecurityHeaders(); } $.ajax(userInfoUrl, { cache: false, headers: headers }).done(AppAuthentication.OnAlreadyLoggedIn).fail(AppAuthentication.OnAccessDenied); }; return authenticateUser(); }};
file: app.authentication.helper.js //application authentication helper var AppAuthenticationHelper = { GetFragment: function () { return GetFragmentItem(); function GetFragmentItem() { if (window.location.hash.indexOf("#") === 0) { return AppAuthenticationHelper.ParseQueryString(window.location.hash.substr(1)); } else { return {}; } } }, GetSecurityHeaders: function() { var accessToken = sessionStorage["accessToken"] || localStorage["accessToken"]; if (accessToken) { return { "Authorization": "Bearer " + accessToken }; } return {}; }, ParseQueryString: function (queryString) { var data = {}, pairs, pair, separatorIndex, escapedKey, escapedValue, key, value; if (queryString === null) { return data; } pairs = queryString.split("&"); for (var i = 0; i < pairs.length; i++) { pair = pairs[i]; separatorIndex = pair.indexOf("="); if (separatorIndex === -1) { escapedKey = pair; escapedValue = null; } else { escapedKey = pair.substr(0, separatorIndex); escapedValue = pair.substr(separatorIndex + 1); } key = decodeURIComponent(escapedKey); value = decodeURIComponent(escapedValue); data[key] = value; } return data; } };
JavaScript Design Patterns
Knowing design patterns help architecting larger JavaScript code structures. Helpful link about "Learning JavaScript Design Patterns" by Addy Osmani:
http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript
e.g. object literal notation
http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript
e.g. object literal notation
var
myObjectLiteral = {
variableKey: variableValue,
functionKey:
function
() {
// ...
}
};
Dienstag, 25. Februar 2014
~/Scripts/app/app.bindings.js
in file BundleConfig.cs in folder App_Start the item "~/Scripts/app/app.bindings.js" is configured but physically not existent in folder Scripts/app. Therefore I removed it from the bundles.Add routine.
The SPA still works fine after that micro refactoring.
before:
bundles.Add(new ScriptBundle("~/bundles/app").Include(
"~/Scripts/app/ajaxPrefilters.js",
"~/Scripts/app/app.bindings.js",
"~/Scripts/app/app.datamodel.js",
"~/Scripts/app/app.viewmodel.js",
"~/Scripts/app/home.viewmodel.js",
"~/Scripts/app/login.viewmodel.js",
"~/Scripts/app/register.viewmodel.js",
"~/Scripts/app/registerExternal.viewmodel.js",
"~/Scripts/app/manage.viewmodel.js",
"~/Scripts/app/userInfo.viewmodel.js",
"~/Scripts/app/_run.js"));
after:
bundles.Add(new ScriptBundle("~/bundles/app").Include(
"~/Scripts/app/ajaxPrefilters.js",
"~/Scripts/app/app.datamodel.js",
"~/Scripts/app/app.viewmodel.js",
"~/Scripts/app/home.viewmodel.js",
"~/Scripts/app/login.viewmodel.js",
"~/Scripts/app/register.viewmodel.js",
"~/Scripts/app/registerExternal.viewmodel.js",
"~/Scripts/app/manage.viewmodel.js",
"~/Scripts/app/userInfo.viewmodel.js",
"~/Scripts/app/_run.js"));
The SPA still works fine after that micro refactoring.
before:
bundles.Add(new ScriptBundle("~/bundles/app").Include(
"~/Scripts/app/ajaxPrefilters.js",
"~/Scripts/app/app.bindings.js",
"~/Scripts/app/app.datamodel.js",
"~/Scripts/app/app.viewmodel.js",
"~/Scripts/app/home.viewmodel.js",
"~/Scripts/app/login.viewmodel.js",
"~/Scripts/app/register.viewmodel.js",
"~/Scripts/app/registerExternal.viewmodel.js",
"~/Scripts/app/manage.viewmodel.js",
"~/Scripts/app/userInfo.viewmodel.js",
"~/Scripts/app/_run.js"));
after:
bundles.Add(new ScriptBundle("~/bundles/app").Include(
"~/Scripts/app/ajaxPrefilters.js",
"~/Scripts/app/app.datamodel.js",
"~/Scripts/app/app.viewmodel.js",
"~/Scripts/app/home.viewmodel.js",
"~/Scripts/app/login.viewmodel.js",
"~/Scripts/app/register.viewmodel.js",
"~/Scripts/app/registerExternal.viewmodel.js",
"~/Scripts/app/manage.viewmodel.js",
"~/Scripts/app/userInfo.viewmodel.js",
"~/Scripts/app/_run.js"));
Abonnieren
Posts (Atom)