-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNotes 20486C.txt
1223 lines (1204 loc) · 139 KB
/
Notes 20486C.txt
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
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
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
219
220
221
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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
[Abbreviations]
Active Server Pages (ASP)
Model-View-Controller (MVC)
Internet Information Services (IIS)
Integrated Development Environment (IDE)
Internet Service Provider (ISP)
Asynchronous JavaScript and XML (AJAX)
JavaScript Object Notation (JSON)
Extensible Markup Language (XML)
Application Program Interface (API)
File Transfer Protocol (FTP)
Secure Sockets Layer (SSL)
Test-Driven Development (TDD)
Unified Modeling Language (UML)
Logical Data Model (LDM)
Windows Communication Foundation (WCF)
Hypertext Transfer Protocol (HTTP)
Object Relational Mapping (ORM)
Language Integrated Query (LINQ)
Entity Framework (EF)
Inversion of Control (IOC)
Dependency Injection (DI)
Search Engine Optimization (SEO)
Content Delivery Network (CDN)
Open Web Interface for .NET (OWIN)
Windows Identity Foundation (WIF)
Security Token Service (STS)
Hypertext Transfer Protocol (HTTP)
[Summary 20486C]
Module 1: Exploring ASP.NET MVC 5
Lesson 1: Overview of Microsoft Web Technologies
Developer Tools (Microsoft Visual Studio)
designing, coding, and debugging any ASP.NET web application, including MVC applications
Hosting Technologies (Microsoft Internet Information Server, Microsoft Azure)
IIS can host any ASP.NET, PHP, or Node.js websites
Database Technologies (Microsoft SQL Server, Microsoft Azure SQL Database)
Code Execution Technologies (Server-Side Execution + Client-Side Execution)
Programming Models (Web Pages, Web Forms, MVC)
use MVC to separate server-side code into three parts:
• MVC model defines a set of classes that represent the object types that the web application manages
• MVC view is a component that builds the webpages that make up the web application’s user interface
• MVC controller is a class that handles user interaction, creates and modifies model classes, and selects appropriate views
ASP.NET API
use classes within the System.Web namespace to rapidly implement common website functionalities:
• Configuration (System.Web.Configuration)
• Authentication and Authorization (System.Web.Security)
• Caching (System.Runtime.Caching)
Compiling ASP.NET Code (Compilation to MSIL vs Compilation to native code)
use pre-compilation to avoid delays and to protect source code
Client-Side Web Technologies (JavaScript, jQuery, jQuery UI, jQuery Mobile, AJAX)
Internet Information Server Features
IIS is tightly integrated with ASP.NET, Visual Studio 2017, and Windows Server:
• Deployment Protocols. The advanced Web Deploy protocol, which is built into Visual Studio 2017, automatically manages the deployment of a website with all its dependencies. Alternatively, you can use File Transfer Protocol (FTP) to deploy content.
• Centralized Web Farm Management. When you run a large website, you can configure a load-balanced farm of many IIS servers to scale to large sizes. IIS management tools make it easy to deploy sites to all servers in the farm and manage sites after deployment.
• High Performance Caches. You can configure ASP.NET to make optimal use of the IIS caches to accelerate responses to user requests. When IIS serves a page or other content, it can cache it in memory so that subsequent identical requests can be served faster.
• Authentication and Security. IIS supports most common standards for authentication, including Smart Card authentication and Integrated Windows authentication. You can also use Secure Sockets Layer (SSL) to encrypt security-sensitive communications, such as logon pages and pages containing credit card numbers.
• ASP.NET Support. IIS is a web server that fully supports ASP.NET.
• Other Server-Side Technologies. You can host websites developed in PHP and Node.js on IIS.
Scaling Up IIS
• scalability
• resilience
Perimeter Networks
A perimeter network has a network segment that is protected from the Internet through a firewall that validates and permits incoming HTTP requests. A second firewall, which permits requests only from the web server, separates the perimeter network from the internal organizational network.
IIS Express
Other Web Servers (Apache, nginx)
Microsoft Azure
• Flexible Scaling
• Flexible Pricing
host (Web Apps, API Apps, Databases, Virtual Servers, Mobile Services, Media Services)
Lesson 2: Overview of ASP.NET
Web Pages Applications
The Web Pages programming model has the following advantages:
• It is simple to learn.
• It provides precise control over the rendered HTML.
Using a Web Pages site has some disadvantages:
• It provides no control over URLs that appear in the Address bar.
• Large websites require large numbers of pages, each of which must be coded individually.
• There is no separation of business logic, input logic, and the user interface.
Web Forms Applications
Web Forms Controls:
• Input controls, such as text boxes, option buttons, and check boxes.
• Display controls, such as image boxes, image maps, and ad rotators.
• Data display controls, such as grid views, form views, and charts.
• Validation controls, which check data entered by the user.
• Navigation controls, such as menus and tree views.
Web Forms Code Files (web page + code behind)
Binding Controls to Data
The Web Forms programming model has the following advantages:
• You can design your page visually by using server controls and Design View.
• You can use a broad range of highly functional controls that encapsulate a lot of functionality.
• You can display data without writing many lines of server-side code.
• The user interface in the .aspx file is separated from input and business logic in the code-behind files.
Using a Web Forms site has some disadvantages:
• The ASP.NET Web Forms page life cycle is an abstraction layer over HTTP and can behave in unexpected ways. You must have a complete understanding of this life cycle, to write code in the correct event handlers.
• You do not have precise control over markup generated by server-side controls.
• Controls can add large amounts of markup and state information to the rendered HTML page. This increases the time taken to load pages.
MVC Applications
The MVC programming model has the following advantages:
• Views enable the developer to take precise control of the HTML that is rendered.
• You can use the Routing Engine to take precise control of URLs.
• Business logic, input logic, and user interface logic are separated into Models, Controllers, and Views.
• Unit testing techniques and Test Driven Development (TDD) are possible.
Using an MVC site has some disadvantages:
• MVC is potentially more complex to understand than Web Pages or Web Forms.
• MVC forces you to separate your concerns (models, views, and controllers). Some programmers may find this challenging.
• You cannot visually create a user interface by dragging controls onto a page.
• You must have a full understanding of HTML, CSS, and JavaScript to develop Views.
Shared ASP.NET Features
• Configuration
• Authentication
• Membership and Roles
• State Management
• Caching
Lesson 3: Introduction to ASP.NET MVC 5
Models, Views and Controllers
Models and Data
Controllers and Actions
• Controllers inherit from the System.Web.Mvc.Controller base class.
• Actions usually return a System.Web.Mvc.ActionResult object.
Views and Razor
• A view is, by default, a .cshtml or .vbhtml file that includes both HTML markup and programming code.
• A view engine interprets view files, runs the server-side code, and renders HTML to the web browser.
• Razor is the default view engine in ASP.NET MVC 5.
Request Life Cycle
Module 2: Designing ASP.NET MVC 5 Web Applications
Lesson 1: Planning in the Project Design Phase
Project Development Methodologies
• Waterfall Model:
• Feasibility analysis. In this phase, planners and developers study and determine the approaches and technologies that can be used to build the software application.
• Requirement analysis. In this phase, planners and analysts interview the users, managers, administrators, and other stakeholders of the software application to determine their needs.
• Application design. In this phase, planners, analysts, and developers record a proposed solution.
• Coding and unit testing. In this phase, developers create the code and test the components that make up the system individually.
• Integration and system testing. In this phase, developers integrate the components that they have built and test the system as a whole.
• Deployment and maintenance. In this phase, developers and administrators deploy the solution so that users can start using the software application.
• Iterative Development Model
• Prototyping Model
• Agile Software Development Model:
• Incremental development. Software is developed in rapid cycles that build on earlier cycles. Each iteration is thoroughly tested.
• Emphasis on people and interactions. Developers write code based on what people do in their role, rather than what the development tools are good at.
• Emphasis on working software. Instead of writing detailed design documents for stakeholders, developers write solutions that stakeholders can evaluate at each iteration to validate if it solves a requirement.
• Close collaboration with customers. Developers discuss with customers and stakeholders on a day-to-day basis to check requirements.
• Extreme Programming
• Test Driven Development
Unified Modeling Language:
• Behavior diagrams. These diagrams depict the behavior of users, applications, and application components.
• Interaction diagrams. These diagrams are a subset of behavior diagrams that focus on the interactions between objects.
• Structure diagrams. These diagrams depict the elements of an application that are independent of time. This means they do not change through the lifetime of the application.
Gathering Requirements:
• Functional requirements. These requirements describe how the application behaves and responds to users. Functional requirements are often called behavioral requirements. They include:
• User interface requirements. These requirements describe how the user interacts with an application.
• Usage requirements. These requirements describe what a user can do with the application.
• Business requirements. These requirements describe how the application will fulfill business functions.
• Technical requirements. These requirements describe technical features of the application and relate to availability, security, or performance. These requirements are sometimes called non-functional or non-behavioral requirements.
Usage Scenarios and Use Cases:
• A usage scenario is a specific real-world example, with names and suggested input values, of an interaction between the application and a user.
• A use case is similar to a usage scenario, but is more generalized. Use cases do not include user names or input values. They describe multiple paths of an interaction, which depends on what the user provides as input or other values.
Agile Requirements Modeling:
• Initial requirement modeling. In the initial design phase, developers identify and record a few broad use cases in an informal manner without full details.
• Just-in-time modeling. Before writing code that implements a use case, a developer discusses it with the relevant users. At this point, the developer adds full details to the use case. In an agile development project, developers talk to users and other stakeholders at all times, and not just at the beginning and end of the project.
• Acceptance testing. An acceptance test is a test that the application must pass for all stakeholders to accept and sign off the application. When you identify a functional requirement, you can also specify a corresponding acceptance test that must be run to ensure that the requirements are met.
User Stories in Extreme Programming
Planning the Database Design:
Logical Modeling
Physical Database Structure:
• Tables
• Views
• Stored Procedures
• Security
Working with Database Administrators
Database Design in Agile Development and Extreme Programming
Planning for Distributed Applications:
Distributed web applications often use a layered architecture:
• Presentation layer. Components in this layer implement the user interface and presentation logic. If you are building an MVC web application, views and controllers make up your presentation layer.
• Business logic layer. Components in this layer implement high-level business objects such as products, or customers. If you are building an MVC web application, models make up your business logic layer.
• Data access layer. Components in this layer implement database access operations and abstract database objects, such as tables, from business objects. For example, a product business object may include data from both the Products and StockLevels database tables. If you are building an MVC web application, models often make up both business logic and data access layers. However, with careful design and coding practices, it is possible to refactor code to separate these layers.
• Database layer. This layer has the database itself.
Communication Between Layers:
• Between the browser and presentation layer web server. In any web application, the web browser, where the presentation layer runs, communicates with the web server by using HTTP. If authentication is required, it is often performed by exchanging plain text credentials. You can also use Secure Sockets Layer (SSL) to encrypt this sensitive communication.
• Between the web server and the middle-tier server. The communication and security mechanisms used for communication between the web server and the middle-tier server depends on the technology that you use to build the business logic components:
• Web services: If you implement business objects and data access classes as web services, the presentation layer components communicate with the web services by using HTTP. You can perform authentication by using the Kerberos protocol that is a part of Windows Integrated Authentication or by using plain text encrypted with SSL.
• Windows Communication Foundation (WCF) services: If you implement business objects and data access classes as WCF services, you can choose between two hosting mechanisms. You can host the WCF services within IIS, in which case, HTTP is the transport mechanism and SSL is the security mechanism. You can also host the WCF services within a Windows Process Activation Service (WAS), in which case, you can use TCP, Microsoft Message Queuing (MSMQ), or named pipes as the transport mechanism.
• Between middle-tier server and database. The middle-tier server sends T-SQL queries to the database server, which authenticates against the database by using the required credentials that are often included in the connection string.
Planning State Management:
In application development, the application state refers to the values and information that are maintained across multiple operations. Hypertext Transfer Protocol (HTTP) is fundamentally a stateless protocol, which indicates that it has no mechanism to retain state information across multiple page requests. However, there are many scenarios, such as the following, which require state to be preserved:
• User preferences. Some websites enable users to specify preferences. For example, a photo sharing web application might enable users to choose a preferred size for photos. If this preference information is lost between page requests, users have to continually reapply the preference.
• User identity. Some sites authenticate users to provide access to members-only content. If the user identity is lost between page requests, the user must re-enter the credentials for every page.
• Shopping carts. If the content of a shopping cart is lost between page requests, the customer cannot buy anything from your web application.
• Client-Side State Storage:
• Cookies. Cookies are small text files that you can pass to the browser to store information. A cookie can be stored:
• In the client computer memory, in which case, it preserves information only for a single user session.
• On the client computer hard disk drive, in which case, it preserves information across multiple sessions.
• Most browsers can store cookies only up to 4,096 bytes and permit only 20 cookies per website. Therefore, cookies can be used only for small quantities of data. Also, some users may disable cookies for privacy purposes, so you should not rely on cookies for critical functions.
• Query strings. A query string is the part of the URL after the question mark and is often used to communicate form values and other data to the server. You can use the query string to preserve a small amount of data from one page request to another. All browsers support query strings, but some impose a limit of 2,083 characters on the URL length. You should not place any sensitive information in query strings because it is visible to the user, anyone observing the session, or anyone monitoring web traffic.
• Server-Side State Storage:
The following locations store state information in server memory:
• TempData. This is a state storage location that you can use in MVC applications to store values between one request and another. You can store values by adding them to the TempData collection. This information is preserved for a single request only and is designed to help maintain data across a webpage redirect. For example, you can use it to pass an error message to an error page.
• Application State. This is a state storage location that you can use to store vales for the lifetime of the application. The values stored in application state are shared among all users. You can store values by adding them to the Application collection. If the web server or the web application is restarted, the values are destroyed. The Application_Start() procedure in the Global.asax file is an appropriate place to initialize application state values. Application state is not an appropriate place to store user-specific values, such as preferences, because if you store a preference in application state, all users share the same preference, instead of having their own unique value.
• Session state. The Session collection stores information for the lifetime of a single browser session and values stored here are specific to a single user session; they cannot be accessed by other users. By default, if the web server or the web application is restarted, the values are destroyed. However, you can configure ASP.NET to store session state in a database or state server. If you do this, session state can be preserved across restarts. Session state is available for both authenticated users and anonymous users. By default, session state uses cookies to identify users, but you can configure ASP.NET to store session state without using cookies.
The following locations store state information in server harddisk:
• Profile properties. If your site uses an ASP.NET profile provider, you can store user preferences in profiles. Profile properties are persisted to the membership database, so they will be kept even if the web application or web server restarts.
• Database tables. If your site uses an underlying database, like most sites do, you can store state information in its tables. This is a good place to store large volumes of state data that cannot be placed in server memory or on the client computer. For example, if you want to store a large volume of session-specific state information, you can store a simple ID value in the Session collection and use it to query and update a record in the database.
Planning Globalization and Localization:
Globalization vs Localization:
• The process by which you make a web application available in multiple languages is called globalization or internationalization.
• The process by which you make a web application available in a specific language and culture is called localization.
There is an internationally-recognized set of language codes that specify a culture on the Internet: language-region.
Using Resource Files
Using Separate Views
Lesson 2: Designing Models, Controllers, and Views
Designing Models:
A fundamental activity in the MVC design process is designing a model. Each model class within the model represents a kind of object that your application manages. You cannot plan for controllers and views until you understand the structure and design of the model.
Identifying Model Classes and Properties
Domain Model and Logical Data Model Diagrams
Relationships and Aggregates (one-to-one, one-to-many, or many-to-many)
Entity Framework:
• Database-First. Use the Entity Framework in the database-first mode when you have a pre-existing database to work with. This may happen because you already have data from an earlier system or because a DBA has designed the database for you. You can also choose this mode if you are familiar with creating databases in a database administration tool, such as Microsoft SQL Server Management Studio. When you use this mode, you have to specify the database connection string. Entity Framework connects to the database and examines the database schema. It creates a set of classes for you to use for data access.
• Model-First. Use Entity Framework in the model-first mode when you do not have a pre-existing database and prefer to design your model in Visual Studio. You can use the Entity Designer tool to name, configure, and link your model classes. This creates XML files that Entity Framework uses both to create model classes and to create the database with its tables and relationships.
• Code-First. Use Entity Framework in the code-first mode when you have no pre-existing database and prefer to design your models entirely in C# code. Your code must include DBContext and DBSet objects—these correspond to the database and its tables. When you run the application for the first time, Entity Framework creates the database for you.
Design in Agile and Extreme Programming
Designing Controllers:
Identify Controllers and Actions
Design in Agile and Extreme Programming
Designing Views:
Views, Template Views, and Partial Views
Creating Wireframes
Design in Agile and Extreme Programming
Module 3: Developing ASP.NET MVC 5 Models
Lesson 1: Creating MVC Models
Developing Models
Using Display and Edit Data Annotations on Properties
The model classes usually specify three attributes for each property:
• The name of the property, for example, Title
• The data type of the property, for example, String
• The access levels of the property, for example, the get and set keywords to indicate read and write access
Additionally, by using attributes, you can supply additional metadata to describe properties to ASP.NET MVC. The MVC runtime uses this metadata to determine how to render each property in views for displaying and editing. These attributes are called display and edit annotations.
Annotations from System.ComponentModel.DataAnnotations:
• DisplayName
• DataType
• DisplayFormat
Validating User Input with Data Annotations
Using Validation Data Annotations:
• Required (+ ErrorMessage)
• Range
• StringLength
• RegularExpression
Model Binders:
• What Are Model Binders?
A model binder is a component of an ASP.NET MVC application that creates an instance of a model class, based on the data sent in the request from the web browser.
• What Does a Model Binder Do?
A model binder ensures that the right data is sent to the parameters in a controller action method.
The Controller Action Invoker and the Default Model Binder
How the Default Model Binder Passes Parameters
In a default MVC application, there is only one model binder for the ControllerActionInvoker to use. This binder is an instance of the DefaultModelBinder class. The default model binder passes parameters by using the following logic:
1. The binder examines the definition of the action that it must pass parameters to.
2. The binder searches for values in the request that can be passed as parameters. The binder searches for values in the following locations, in order:
a. Form Values. If the user fills out a form and clicks a submit button, you can find parameters in the Request.Form collection.
b. Route Values. Depending on the routes that you have defined in your web application, the model binder may be able to identify parameters in the URL. In the example URL, “45” is identified as a parameter by the default MVC route.
c. Query Strings. If the user request includes named parameters after a question mark, you can find these parameters in the Request.QueryString collection.
d. Files. If the user request includes uploaded files, these can be used as parameters.
Notice that if there are form values and route values in the request, form values take precedence. Query string values are only used if there are no form values and no route values available as parameters.
Model Extensibility:
Custom Validation Data Annotations
inherit from System.ComponentModel.DataAnnotations.ValidationAttribute
example: LargerThanValidation
Custom Model Binders
implement System.Web.Mvc.IModelBinder
example: CarModelBinder
Lesson 2: Working with Data
Connecting to a database
ADO.NET and Databases
use the ADO.NET technology to access databases (System.Data)
ADO.NET supports a wide range of databases by using different data providers:
• Microsoft SQL Server. This is an industry-leading database server from Microsoft. ADO.NET includes the SqlClient provider for all SQL Server databases.
• Microsoft SQL Server Express. This is a free version of SQL Server that includes a wide range of database functionality and is very flexible. Some advanced capabilities are not possible with SQL Express. The SqlClient provider is used for SQL Express.
• OLE DB. This is a standard that many different databases adhere to. ADO.NET includes the OleDb provider for all OLE DB databases.
• ODBC. This is another older standard that many different databases adhere to. ADO.NET includes the Odbc provider for all ODBC databases. In general, you should use an OLE DB provider, if it is available, instead of an ODBC provider.
• You can also use third-party ADO.NET providers to access other databases.
Cloud Databases
Microsoft Azure SQL Database has the following advantages:
• Databases run in Microsoft data centers with the best connectivity and reliability.
• Microsoft guarantees up to 99% uptime.
• You do not need to build and maintain your own database servers or employ database administrators.
• You can scale up the databases very easily.
• You pay only for the data that you use and distribute.
You can use Microsoft Azure SQL Database with ADO.NET by using the SqlClient provider.
Connecting an MVC Web Application to a Database:
• Add a reference to the System.Data namespace.
• Add a connection string to the Web.config file. This string specifies the provider, the location of the database, the security properties, and other properties depending on the provider. The <connectionStrings> tag must appear within the <configuration> tag, after the <configSections> tag.
Entity Framework
Entity Framework is an Object Relational Mapping (ORM) framework.
An ORM framework maps the tables and columns found in a database to objects and their properties that you can call from .NET code.
Entity Framework Workflows:
• Database-First. You can use the database-first workflow when you have a pre-existing database or if you prefer to create a new database by defining table, columns, views, and other database schema objects. In this workflow, Entity Framework examines the database and creates an XML file with an .edmx extension called the model file. The model file describes classes that you will be able to work with, in code. You can adjust the model by using a designer in Visual Studio and then writing code against the Entity Framework classes.
• Model-First. You can use the model-first workflow when you do not yet have a database and you prefer to design your model by using an ORM modeling tool. In this workflow, you create the .edmx file in the Visual Studio designer and then write code against the model classes generated by the designer. When you run the application, Entity Framework creates the database tables and columns to support the model. In this workflow, Visual Studio can also create a connection string for you and insert it into Web.config, based on the database that you specify.
• Code-First. You can use the code-first workflow if you prefer to create a model by writing .NET Framework classes. In this workflow, there is no model file. Instead, you create model classes in C# or Visual Basic. When you run the application, if the database doesn’t exist, Entity Framework creates the database.
Code-First Workflow:
create database and tables using repository and model classes:
• repository class should inherit from System.Data.Entity.DbContext
• within repository class use System.Data.Entity.DbSet<> for each model / database table
• Entity Framework looks for a connection string with name of repository class
Using an Entity Framework Context:
using an Entity Framework context in a controller:
• DbSet.Find(Object[]) Method:
Finds an entity with the given primary key values. If an entity with the given primary key values exists in the context, then it is returned immediately without making a request to the store. Otherwise, a request is made to the store for an entity with the given primary key values and this entity, if found, is attached to the context and returned. If no entity is found in the context or the store, then null is returned.
using Initializers to Populate Databases (code-first or model-first workflow):
• use an initializer class to populate database with sample data which ensures that there is sample data to work with during development
• DropCreateDatabaseAlways<TContext> Class:
An implementation of IDatabaseInitializer that will always recreate and optionally re-seed the database the first time that a context is used in the app domain. To seed the database, create a derived class and override the Seed method.
• DropCreateDatabaseIfModelChanges<TContext> Class:
An implementation of IDatabaseInitializer that will DELETE, recreate, and optionally re-seed the database only if the model has changed since the database was created.
• Database.SetInitializer(IDatabaseInitializer<TContext>) Method (Global.asax > Application_Start):
Sets the database initializer to use for the given context type. The database initializer is called when a the given DbContext type is used to access a database for the first time. The default strategy for Code First contexts is an instance of CreateDatabaseIfNotExists<TContext>.
Using LINQ to Entities:
Language Integrated Query (LINQ) is a set of extensions to Visual C# and Visual Basic that enable you to write complex query expressions.
You can use these expressions to extract data from databases, enumerable objects, XML documents, and other data sources.
LINQ to Entities is the version of LINQ that works with Entity Framework.
Data Access in Models and Repositories
In MVC applications, you can place the data access code in the model, along with the business logic.
However, many software architects prefer to separate these two types of code because they serve different purposes:
• Business Logic. This code defines the objects that the web application manages, their properties, and their relationships with each other.
• Data Access Logic. This code defines the operations necessary to persist data to a database. This includes operations to create new records, read records, update records, and delete records in database tables. A single object in the business logic layer may take data from multiple database tables. This abstraction is handled by the data access logic.
MVC does not require you to separate business and data access logic, and you can create MVC model classes that implement both layers. This is often done in small or simple web applications with small development teams. In these scenarios, Entity Framework classes are used directly in the model classes.
In more complex situations, you need to place the business logic in MVC model classes and place the data access logic in dedicated classes called repositories. When you take this approach, model classes are independent of the database structure and do not include code that depends on database table names, column names, or view names. This approach makes it easier to redesign the database or move to a different data store or data access technology, without the need to re-code your entire application. Using this approach, you employ the Entity Framework in your repository classes, but not in your model classes.
How to Separate Model Classes and Repositories:
If you do choose to separate business logic and data access logic, you must take the following steps for each model class:
1. Define an interface for the repository class. This interface declares the methods that the repository class uses to read and write data from and to the database.
2. Create and write code for the repository class. This class must implement all the data access methods declared in the interface.
3. Remove all data access code from the model class.
4. Modify the controller class to use the repository class. Instead, create an instance of the repository class and call its methods to create the model.
Module 4: Developing ASP.NET MVC 5 Controllers
Lesson 1: Writing Controllers and Actions
A controller is a .NET Framework class that inherits from the System.Web.Mvc.Controller base class. Controllers respond to user requests. Within a controller class, you create actions to respond to user requests. Actions are methods within a controller that return an ActionResult object. The ActionResult object is often a view that displays a response to the user request; however, it can also yield other types of results.
Responding to User Requests
When an MVC web application receives a request from a web browser, the following events happen in sequence:
1. An MvcHandler object creates a controller factory. The controller factory is the object that instantiates a controller to respond to the request. Usually, this factory is a DefaultControllerFactory object, but you can create a custom controller factory, if necessary. The MvcHandler object chooses the controller factory based on the RequestContext object, which has information about the request that the user made.
2. The controller factory creates a Controller object, and the MvcHandler calls the Execute method in that controller.
3. The ControllerActionInvoker examines the RequestContext object and determines the action to call in the Controller object.
4. The ControllerActionInvoker uses a model binder to determine the values to be passed to the action as parameters.
5. The ControllerActionInvoker runs the action. Often, the action creates a new instance of a model class, perhaps by querying the database with the parameters that the invoker passed to it. This model object is passed to a view, to display results to the user. Action methods can do many other things such as rendering views and partial views, redirecting to other websites, displaying snippets of content, or displaying other files.
The User Request
Users of web browsers make requests either by typing a URL into the Address bar of the browser, or by clicking a link to some address within your website. Such links can either be within your website, in which case you can control how they are rendered, or from an external website. Whether the request originates from within the website or from an external website, it can include information that controller actions can use as parameters. Consider the following examples:
• http://www.adventure-works.com/: This URL is the home page of the website and specifies no further information.
• http://www.adventure-works.com/photo: This URL specifies an extra value, photo. By default, the MvcHandler interprets this as the name of a controller.
• http://www.adventure-works.com/photo/index: This URL specifies a second value, index. By default, the MvcHandler interprets this as the name of an action within the controller.
• http://www.adventure-works.com/photo/display/1: This URL specifies a third value, 1. By default, the ControllerActionInvoker interprets this as a parameter to pass to the action method.
• http://www.adventure-works.com/photo/display?id=1: This URL includes a query string, id=1. The model binder examines the Display actions in the Photo controller. If it finds an action with a parameter called id, it calls that action and passes 1 as a parameter.
Writing Controller Actions
Controller actions are public methods that return an ActionResult object. Alternatively, actions can return objects of many other classes that derive from the ActionResult class.
[HttpGet] default vs [HttpPost], [HttpPut], [HttpDelete]
ModelState.IsValid property is used to check whether the user has submitted valid data
Possible Return Classes:
• Action methods are usually defined with the ActionResult class as the return type. ActionResult is a base class, and you can use a range of derived classes to return different responses to the web browser.
• Controller actions usually return a view and pass a model class to it, for display. You can create an action that calls the View() helper, and creates and returns a ViewResult object. The View() helper is available when you derive from the base Controller class.
• Alternatively, you can return an HTTP error (HttpNotFound()).
• To return files, you can use the File() helper to return a FileContentResult object.
• Other possible action results include:
• PartialViewResult. You can use this action to generate a section of an HTML page, but not a complete HTML page. Partial views can be re-used in many views throughout a web application.
• RedirectToRouteResult. You can use this action result to redirect the web browser to another action method or another route.
• RedirectResult. You can use this action result to redirect to a specific URL, either inside your web application or to an external location.
• ContentResult. You can use this action result to return text to the web browser. You can return plain text, XML, a comma-separated table, or other text formats. This text can be rendered in the web browser or parsed with client-side code.
Child Actions
When an action returns a complete view, MVC sends a new complete webpage to the web browser for display. Sometimes, you may want to call an action from within a view, to return a piece of content for display within a webpage. A child action is an action method that can return a small piece of content in this manner. The FileContentResult is often a good example of a child action, because the image returned usually forms part of a webpage. Partial views also support child actions.
To declare an action method as a child action, you can use the [ChildActionOnly] annotation. This annotation ensures that the action method can be called only from within a view by using the Html.Action() helper. Using this method, you can prevent a user from calling the child action directly by typing the correct URL into the Address bar.
Using Parameters
The ControllerActionInvoker and the DefaultModelBinder classes obtain parameters from a user request and pass them to action methods. The DefaultModelBinder can locate parameters in a posted form, the routing values, the query string, or in the posted files. If the model binder finds a parameter in the action method that matches the name and type of a parameter from the request, the action method is called and the parameter is passed from the request. This arrangement enables you to obtain and use parameters in your actions.
Passing Information to Views
Using The ViewBag
The ViewBag is a dynamic object that is part of the base controller class. Because it is a dynamic object, you can add properties that are of any type to it, in the action method. In the view, you can use the ViewBag object to obtain the values added in the action.
Using The ViewData Dictionary
The ViewBag object was added to MVC in version 3. In the earlier versions, you could pass extra data to views by using the ViewData dictionary. This feature is still available in MVC 5 for backward compatibility and for developers who prefer to use dictionary objects.
ViewBag is a dynamic wrapper above the ViewData dictionary. This means that you could save a value in a controller action by using ViewBag and read the same value back out by using ViewData.
What Are Controller Factories?
A controller factory is an MVC component that instantiates the controller classes that you create.
How the DefaultControllerFactory Class Locates a Controller Class
The DefaultControllerFactory class identifies controller classes by using the following criteria:
• The class scope must be public.
• The class must not be marked as abstract.
• The class must not take generic parameters.
• The class must have a name that ends with Controller.
• The class must implement the IController interface.
When the MVC web application starts, DefaultControllerFactory creates a list of all the classes in the application that satisfy these criteria. This list helps to create the correct controller rapidly. To write a controller, you must ensure that all the above mentioned criteria are implemented. Usually, you meet the IController interface criterion by inheriting from the base Controller class.
By default, the DefaultControllerFactory mandates all controller classes to end with the word Controller.
Creating a Custom Controller Factory:
• To modify the criteria for selecting controllers. The criteria described earlier are suitable for most web applications, but sometimes, you may want to change them. For example, you may not want to name controllers with Controller at the end, or you may want to add extra criteria of your own.
• To support direct injection for testing. Direct injection is a programming technique that lets you specify classes at run time, instead of specifying classes when writing code. This is helpful for unit testing because you can inject a test class with mock data, instead of real data. The DefaultControllerFactory class does not support direct injection.
You must implement the CreateController, GetControllerSessionBehavior, and ReleaseController methods for any custom controller factory you create.
Registering a Custom Controller Factory (Global.asax > Application_Start):
• ControllerBuilder.SetControllerFactory Method:
Sets the controller factory by using the specified type.
• example: CustomControllerFactory
Lesson 2: Writing Action Filters
What Are Filters?
Filters are MVC classes that you can use to manage cross-cutting concerns in your web application. You can apply a filter to a controller action by annotating the action method with the appropriate attribute.
You can also apply a filter to every action in a controller by annotating the controller class with the attribute.
Filter Types
Filter Type Interface Default Class Description
Authorization IAuthorizationFilter AuthorizeAttribute Runs before any other filter and before the code in the action method. Used to check a user’s access rights for the action.
Action IActionFilter ActionFilterAttribute Runs before and after the code in the action method.
Result IResultFilter ActionFilterAttribute Runs before and after a result is returned from an action method.
Exception IExceptionFilter HandleErrorAttribute Runs only if the action method or another filter throws an exception. Used to handle errors.
Creating and Using Action Filters
If you have a cross-cutting concern in your web application, you can implement it by creating a custom action filter or a custom result filter. You can create custom filters by implementing the IActionFilter interface or the IResultFilter interface. However, the ActionFilterAttribute base class implements both the IActionFilter and IResultFilter interfaces for you. By deriving your filter from the ActionFilterAttribute class, you can create a single filter that can run code both before and after the action runs, and both before and after the result is returned.
Using a Custom Action Filter
example: SimpleActionFilter
Module 5: Developing ASP.NET MVC 5 Views
Lesson 1: Creating Views with Razor Syntax
Adding Views
In an MVC application, there is usually one controller for every model class.
There may be some controllers that do not correspond to any model classes, however each controller can have multiple views.
By convention, an MVC web application creates all views within the top-level Views folder. Within this folder, there is a folder for each controller in the application.
Add View dialog box
Property Description
View name This is the name of the view. The view file name is this name with the appropriate extension added. The name you choose should match the name returned by the corresponding controller action. If the action controller does not specify the name of the view to use, MVC assumes the name of the view matches the name of the controller action.
Model class If you create a strongly-typed view, you need to specify the model class to bind to the view. Visual Studio will use this class when it formulates IntelliSense prompts and checks for compile-time errors.
Template A template is a basic view that Visual Studio can use to create the view. If you specify a model class for the view, Visual Studio can create simple templates for Create, Edit, Details, Delete, and List views. When you become more experienced in using views, you may prefer to build a view from the empty scaffold template, rather than use populated scaffold templates.
Reference script libraries When you select this check box, links to common client-side script files are included in the view. These links include the jQuery JavaScript library.
Create as a partial view A partial view is a section of Razor code that you can re-use in multiple views in your application.
Use a layout page A layout page can be used to impose a standard layout and branding on many pages within the web application.
Differentiating Server Side Code from HTML
The Razor view engine interprets view files and runs any server-side code contained in the view files. To do this, Razor must distinguish server-side code from HTML content that should be sent to the browser unchanged.
The Razor view engine looks for the @ symbol to identify server-side code.
A section of code marked with the @ symbol is referred to as a Razor code expression. In Razor syntax, you mark the start of a Razor code expression with the @ symbol. Razor lacks an expression ending symbol. Instead, Razor infers the end of a code expression by using a fairly sophisticated parsing engine.
Modifying the Interpretation of Code and Content
If you want to display an @ symbol in the browser, you use @@. Razor interprets this as an escape sequence and renders a single @ symbol. This technique is useful for rendering email addresses.
Razor has sophisticated logic to distinguish code from content and often the @ symbol is all that is required. However, occasionally, you may find that an error occurs because Razor misinterprets content as code. To fix such errors, you can use the @: delimiter, which explicitly declares a line as content and not code.
If you want to declare several lines as content, use the <text> tag instead of the @: delimiter. Razor removes the <text> and </text> tags before returning the content to the browser.
HTML Encoding
For security reasons, when Razor runs any server-side code that returns a string, it encodes the string as HTML before rendering it to the browser.
If you have used the normal @Model.HtmlComment syntax to return the formatted comment text, Razor encodes “<” as “<” and “>” as “>” in the HTML source. This results in the user seeing “<i>” on the webpage. This is not the behavior you intend because you want the users to see italicized text.
To render text without HTML encoding, use the Html.Raw() helper. For example, use @Html.Raw(Model.HtmlComment).
You should only use the Html.Raw() helper when it is absolutely necessary. Also, if you must use the Html.Raw() helper, you must ensure that it does not operate on unchecked strings entered by users.
Features of Razor Syntax
Razor Comments
@* This text will not be rendered by the Razor view engine, because this is a comment. *@
Implicit Code Expressions and Parentheses
Razor uses implicit code expressions to determine parts of a line that are server-side code. Usually, implicit code expressions render the HTML you want, but occasionally, you might find that Razor interprets an expression as HTML when it should be run as server-side code.
use Parentheses to Explicitly Delimit Expressions:
<span>Price Including Sales Tax: @Model.Price * 1.2</span> (implicit)
<span>Price Including Sales Tax: @(Model.Price * 1.2)</span> (explicit)
Razor Code Blocks, Loops, and Conditions
example:
@
{
//Razor interprets all text within these curly braces as server-side code.
}
example:
@if (Model.InStock)
{
Html.ActionLink("Buy This Product", "AddToCart")
}
example:
@foreach (var item in Model)
{
<div>@item.ProductName</div>
}
Binding Views to Model Classes and Displaying Properties
Many Razor views are designed to display properties from a specific model class. If you bind such views to the class they display, you get extra help such as IntelliSense feedback as you write the Razor code. Other views may display properties from different model classes in different cases, or may not use a model class at all. These views cannot be bound to a model class and are called dynamic views.
Strongly-Typed Views:
A strongly-typed view is a view that includes a declaration of the model class.
A strongly-typed view only works with an object of the model class in the declaration.
example: @model MyWebSite.Models.Product + @Model.CatalogNumber
Binding to an Enumerable List
example:
@model IEnumerable<MyWebSite.Models.Product>
<h1>Product Catalog</h1>
@foreach (var Product in Model)
{
<div>Name: @Product.Name</div>
}
Using Dynamic Views:
Create a view that can display more than one model class.
A dynamic view does not include the @model declaration at the top of the page.
Check the property for null before you use it.
Rendering Accessible HTML
You render accessible HTML by writing views that follow accessibility guidelines.
You can ensure that your content is accessible to the broadest range of users by adhering to the following guidelines:
• Do not rely on color differences to highlight text or other content. For example, links should be underlined or formatted in bold font to emphasize them to color-blind users.
• Always provide equivalent alternative content for visual and auditory content. For example, always complete the alt attribute for images. Use this attribute to describe the image so that text-to-speech software or text-to-Braille hardware can render meaningful words to the user.
• Use markup and style sheets to separate content from structure and presentation code. This helps text interpretation software to render content to users without being confused by structural and presentation code. For example, you should apply the following best practices to display content on your webpage:
o Avoid using tables to display the content. You should use tables only to present tabulated content. Tables can be used to render graphics and branding on a webpage, but in an accessible site, use positional style sheets to display content. Text readers do not read style sheets.
o Avoid using nested tables. In a nested table, a table cell contains another table. These are particularly confusing to text readers because they read each table cell in a sequential order. The user is likely to become disoriented and unable to determine which cell is being read and what it means.
o Avoid using images that include important text. Text readers cannot render text from within an image file. Instead, use markup to render this text.
Lesson 2: Using HTML Helpers
Using Action Helpers
The Html.ActionLink() and Url.Action() helpers enable you to render HTML that calls controller actions.
Html.ActionLink() returns an <a> element with the correct href parameter value when users click a link in a webpage.
Url.Action() helper renders a URL by using the routing engine without rendering the enclosing <a> element.
example: <img alt="This image came from an action" src="@Url.Action("GetImage", new { id = 1 })" />
Using Display Helpers
Html.DisplayNameFor() renders the name of a model class property. Html.DisplayFor() renders the value of a model class property.
You use the Html.DisplayNameFor() helper to render the display name for a property from the model class.
You specify the property of the model class to the Html.DisplayNameFor() HTML helper by using a lambda expression.
example: @Html.DisplayNameFor(model => model.CreatedDate)
If you used a DisplayName annotation to give a more descriptive name to a property, then Html.DisplayNameFor() will use that DisplayName annotation value; otherwise, it will render the name of the property.
The Html.DisplayFor() helper considers any display annotations that you specify in the model class, and then renders the value of the property.
example: This was created on: @Html.DisplayFor(model => model.CreatedDate)
If you used the DisplayFormat annotation in the model class with DataFormatString set to “{0:dd/MM/yy}”, then the Html.DisplayFor() helper ensures that the date is displayed in short date format.
The Begin Form Helper
To accept user input, you must provide a form on your webpage. A typical form consists of a set of labels and input controls. The labels indicate to the user the property for which they must provide a value. The input controls enable the user to enter a value. Input controls can be text boxes, check boxes, radio buttons, file selectors, drop-down lists, or other types of control. There is usually a submit button and cancel button on forms.
Rendering HTML Forms
To build a form in HTML, you must start with a <form> element in the HTML webpage. All labels and input controls must be within the <form> element. In an MVC view, you can use the Html.BeginForm() helper to render this element and set the controller action to which the form sends data.
In the rendered HTML, the <form> element must be closed with a </form> tag. In Razor views, you can ensure that the form element is closed with an @using code block. Razor renders the </form> tag at the closing bracket of the code block.
example:
@using (Html.BeginForm("Register", "Customer", FormMethod.Post))
{
@* Place input controls here *@
}
Using Forms to Post Files
In HTML, if you want to enable website users to upload files, you should use an HTML form with special properties. Specifically, the <form> element should include the enctype attribute set to the value multipart/form-data and the form must use the POST HTTP verb.
You can specify additional attributes for the <form> element by passing them in an htmlAttributes parameter as new objects.
example:
@using (Html.BeginForm("Create", "Photo", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
@* Place input controls here *@
}
Using Editor Helpers
In Razor views, the Html.LabelFor() and Html.EditorFor() helpers make it easy to render the most appropriate input controls for the properties of a model class.
The Html.LabelFor() helper is similar to the Html.DisplayNameFor() helper because it renders the name of the property that you specify, taking into account the DisplayName annotation if it is specified in the model class. However, unlike the Html.DisplayNameFor() helper, the Html.LabelFor() helper renders a <label> element.
example: @Html.LabelFor(model => model.CreatedDate)
The Html.EditorFor() helper renders HTML <input> elements and other form controls for properties from a model class. This helper renders the most appropriate element for each property data type.
If the string property is annotated with [DataType(DataType.MultilineText)], the Html.EditorFor() helper renders a <textarea> element instead.
example: @Html.EditorFor(model => model.ContactMe)
Using Validation Helpers
Set requirements by using validation data annotations in the model class. In controller actions, you can check the ModelState.IsValid property to verify if a user has entered valid data.
The Html.ValidationSummary() Helper
Use the Html.ValidationSummary() helper to render a summary of all the invalid data in the form. This helper is usually called at the top of the form. When the user submits invalid data, the validation messages are displayed for each invalid field in a bulleted list.
example: [Required(ErrorMessage="Please enter your last name")] + @Html.ValidationSummary()
The Html.ValidationMessageFor() Helper
Use the Html.ValidationMessageFor() helper to render validation messages next to each input in the form.
example: @Html.ValidationMessageFor(model => model.LastName)
Lesson 3: Re-using Code in Views
A partial view renders a section of HTML content that can be inserted into several other views at run time. Because the partial view is a single file that is re-used in several locations, when you implement a change in a single location, the changes are updated in other locations in the web application. Partial views increase the manageability of MVC web applications and facilitate a consistent presentation of content throughout a web application.
Creating Partial Views
You can use partial views to render identical HTML or similar HTML in different locations in your web application.
Creating and Naming Partial Views:
By convention, partial views are named prefixed with an underscore character.
Partial views are often created inside the /Views/Shared folder in your site. Views in the Shared folder are accessible to many controllers.\
Strongly-typed and dynamic partial views
Similar to other views, you can create strongly-typed partial views if you are certain that the partial view will always display the same model class.
Using Partial Views
You can re-use partial views by using the Html.Partial() and Html.Action() HTML helpers.
You can use the Html.Partial() helper to render a partial view within another view file. MVC inserts the HTML that the partial view renders into the parent view and returns the complete webpage to the browser. The first parameter is the name of the partial view file without its file extension. The second optional parameter is a model object for the partial view to render. This is the same model object that the parent view uses because other model objects are not available in this context.
example: @Html.Partial("_Comments")
Remember that you can use the ViewBag and ViewData collections to pass data between the action method and the view. A parent view will share the same ViewBag or ViewData objects with the partial view. This is a good way to share data between the controller action, view, and partial view.
The Html.Action() Helper
You can pass a model object from the parent view to a partial view when you use Html.Partial(). However, the parent view can only pass the same model object available in the parent view. Sometimes, you may want to use a model object different from the parent view, often of a different model class, with the partial view. In such cases, you can use the Html.Action() helper. This calls an action method that returns the correct partial view. The action method can create an instance of any model class.
example: @Html.Action("_CommentsForArticle", "Comment", new { ArticleID = Model.ID })
Module 6: Testing and Debugging ASP.NET MVC 5 Web Applications
Lesson 1: Unit Testing MVC Componwents
A unit test is a procedure that instantiates a component that you have written, calls one aspect of the functionalities of the component, and checks that the component responds correctly according to the design. In object-oriented programming, unit tests usually instantiate a class and call one of its methods. In an MVC web application, unit tests can instantiate model classes or controllers and call their methods and actions.
Why Perform Unit Tests?
There are three types of tests you can use to identify bugs in your application:
• Unit Tests: Unit tests check small aspects of functionality. For example, a unit test may verify the return type of a single method. By defining many unit tests for your project, you can ensure they cover all functional aspects of your web application.
• Integration Tests: Integration tests check how two or more components work together. They can be used to check how two or more classes interact with each other. Integration tests can also be used to check how the entire web application, including the database and external web services, works to deliver content.
• Acceptance Tests: Acceptance tests focus on a functional or technical requirement that must work for the stakeholders to accept the application. Similar to integration tests, acceptance tests usually test multiple components working together.
What Is a Unit Test?
A unit test is a procedure that verifies a specific aspect of functionality. Multiple unit tests can be performed for a single class and even for a single method in a class.
A single unit test usually consists of code that runs in three phases:
1. Arrange. In this phase, the test creates an instance of the class that it will test. It also assigns any required properties and creates any required objects to complete the test. Only properties and objects that are essential to the test are created.
2. Act. In this phase, the test runs the functionality that it must check. Usually, in the Act phase, the test calls a single procedure and stores the result in a variable.
3. Assert. In this phase, the test checks the result against the expected result. If the result matches what was expected, the test passes. Otherwise, the test fails.
How Do Unit Test Help Diagnose Bugs?
Because unit tests check a small and specific aspect of code, it is easy to diagnose the problem when the tests fail. Unit tests usually work with a single class and isolate the class from other classes wherever possible. If other classes are essential, the smallest number of classes are created in the Arrange phase. This approach enables you to fix issues rapidly because the number of potential sources of a bug is small.
Unit tests should check the code that you write and not any infrastructure that the production system will rely on.
Automated Unit Testing
It is important to understand that unit tests, after they are defined, can be rerun quickly and easily throughout the rest of the project life cycle.
This is important because new code can cause bugs at any stage of the development process.
Principles of Test Driven Development
Test Driven Development (TDD), places unit testing at the center of working practices.
Write the Test, Pass the Test, Refactor
In TDD, developers repeat the following short cycle to implement a functional requirement:
1. Write the Test. The developer starts by creating and coding the unit test. This step requires a full understanding of the functional requirement, which can be obtained from use cases or user stories. Because the developer has not written any code in the application, the test fails.
2. Pass the Test. The developer writes some quick and simple code in the application so that it passes the test. During the first iteration, this code is frequently inelegant and may include false assumptions such as hardcoded values.
3. Refactor. The developer cleans up the application code, removes duplicate code, removes hardcoded values, improves readability, and makes other technical improvements. The developer reruns the test to ensure that refactoring has not caused a failure.
The cycle is then repeated. In each iteration, the developer adds a small new element of the final functionality with a corresponding test.
It is important that the code in your tests is treated as production code. It should be well thought out and easy to read so that other developers can understand the test and quickly diagnose any test failures.
Test Driven Development Principles
To use TDD effectively, you must understand its fundamental principles:
• Write tests before code. In the TDD development cycle, the test is created in step one before any code in the application. This means the test must fail the first time it is run. You can understand the test as a specification for the functionality you are building. By writing the test first, you ensure that you begin with a thorough understanding of the problem you are trying to solve.
• Move in small steps. By breaking a large application down into small elements of functionality, you can improve developer productivity. You can do this by giving a developer a small problem to solve in each iteration. The developer can solve the simple problem quickly and understand all the possible circumstances in which their code runs.
• Only write enough code to pass the test. In each iteration, do not be tempted to add extra code that is not related to the test. For example, if you know that users will call an action with other parameters than the ones in the test, do not write code to handle these parameters. Instead, during the next iteration, write a second test for those parameters. Then write and refactor that code.
Developers can refer to tests as examples of how to use a class or method. This can increase developer productivity because developers can view the code that demonstrates the method or class.
Writing Loosely Coupled MVC Components
A loosely coupled application is one in which each component requires few or no details of the other components of the system. In object-oriented programming, for example, two classes can be described as loosely-coupled if one class can call methods on the other class without any code that is specific to the other class. When system components are loosely-coupled in this manner, it is easy to replace a class with another implementation of the same functionality. Loosely coupled components are essential for thorough unit testing because classes that deal with real data, such as data from a database, can be easily be replaced with classes that deal with test data.
Using Loose Coupling in Tests
A loosely-coupled application is easy to test because you can make tests simpler by replacing a fully functional instance of a class with a simplified instance that is specifically designed for the test. Replacing classes in tests in this manner can only be done when components are loosely coupled. Replacement instances used for unit tests are known as test doubles or fakes. A test double or fake includes just enough code and properties to pass the relevant test and prove the functionality.
Other Benefits of Loose Coupling
Loose coupling has other benefits besides testing. Loose coupling makes it easier to replace simple components with more sophisticated ones—for example, in version one of an application you might write a class that calculates a simple arithmetical mean. In version two, you might replace this class with a new class that calculates a weighted mean based on a more complex algorithm. If the components are loosely coupled, you can perform this replacement without modifying any code outside of the averaging classes.
Using Interfaces for Loose Coupling
In object-oriented programming, an interface defines a set of properties and methods. Any class that implements that interface must implement all the properties and methods it defines as a minimum. This creates loose coupling because you need not specify a class in code. Instead, you can specify any implementation of a particular interface.
Loose Coupling in an MVC Web Application
Use in-memory data set up during the Arrange phase. DTherefore, you can test your code without relying on the network connection to the database or the database server itself. This approach also ensures that the test runs quickly, which is important because slow tests discourage developers from running tests regularly.
Writing Unit Tests for MVC Components
The Microsoft ASP.NET MVC 5 programming model is easy to integrate with the principles of unit testing and TDD because of its separation of concerns into model, controllers, and views. Models are simple to test because they are independent classes that you can instantiate and configure during the Arrange phase of a test. Controllers are simple classes that you can test, but it is complex to test controllers with in-memory data, rather than using a database. To test controllers with in-memory data, you create a test double class, also known as a fake repository. Objects of this class can be populated with test data in memory without querying a database. You need to understand how to write test doubles and how to write a typical test for MVC classes.
Add and Configure a Test Project
In a Visual Studio test project, test fixtures are classes marked with the [TestClass] annotation. Unit tests are methods marked with the [TestMethod] annotation. Unit tests usually return void but call a method of the Assert class, such as Assert.AreEqual() to check results in the test Assert phase.
Test Model Classes and Business Logic
In MVC, model classes do not depend on other components or infrastructure. You can easily instantiate them in-memory, arrange their property values, act on them by calling a method, and assert that the result was as expected. Sometimes, you create business logic in the model classes, in which case the Act phase involves calling a method on the model class itself. If, by contrast, you have created a separate business logic layer, code in the Act phase must call a method on the business object class and pass a model class.
Create Repository Interfaces
Implement and Use a Repository in the Application
The repository interface defines methods for interacting with data but does not fix how that data will be set and stored. You must provide two implementations of the repository:
• An implementation of the repository for use in production and development. This implementation will use data from the database or some other storage mechanism.
• An implementation of the repository for use in tests. This implementation will use data from the memory set during the Arrange phase of each test.
example: WebStoreContext
Implement a Repository Test Double
example: FakeWebStoreContext
Using the Test Double to Test a Controller
Specifying the Correct Context
Scenario Context
In unit tests In a unit test, you should test code without relying on underlying infrastructure such as databases. You can use a test double class that behaves like an Entity Framework context, but uses in-memory data.
At other times When you are not unit testing the code, you use an actual Entity Framework context in your controller code, which interacts with a database.
Using Constructors to Specify a Repository
You can specify the correct repository to use in a test by using controller constructors. During a unit test, call a controller constructor that takes an instance of the repository interface as a parameter. At other times, the MVC controller factory will call the controller constructor without any parameters.
Using Inversion of Control Containers
You can also ensure that the correct repository class is used in each context by using an Inversion of Control (IoC) container. An IoC container is a framework that you can add to your application that instantiates classes. You must configure the IoC container so that it can identify the kind of object to create when the application expects a specific interface.
By using an IoC container, you avoid the need to create two constructors for controller classes. During tests, you can instantiate the test double and pass it to the controller constructor. At other times, the IoC container instantiates the actual Entity Framework context and passes it to the controller constructor.
Using Mocking Frameworks
When you write a unit test, you must, during the Arrange phase, create test data on which the test will run. By using a test double or mock object to supply test data, you can test your code in isolation from other classes and from the infrastructure elements such as databases and network connections on which the application will rely. You can create test doubles by manually coding their instantiation, setting their properties, and populating collections. Such test doubles are known as manual mock objects.
Alternatively, instead of creating mock objects manually with your own code, you can use a mocking framework to automate this work. A mocking framework automatically creates mock object by using the interfaces that you specify. In the case of IoC containers, there are many mocking frameworks that can be used in testing MVC web applications.
Why Use a Mocking Framework?
There are many situations in which mocking frameworks can significantly ease unit testing. Even for simple tests, mocking frameworks reduce the amount of setup code that you have to develop. After you become familiar with the mocking framework that you choose, and have learned how to write arrangement code for it, you will begin to save time. In more complex situations, such as the following, mocking frameworks have great advantages:
• Creating multiple mock objects of a single type. You should try to keep each unit test as simple as possible, but inevitably, some tests require many mock objects to work with. For example, if you are testing a method that underlies paging functionality in your web application, you must create enough mock objects to populate multiple pages. Mocking frameworks can automate the creation of multiple mock objects of the same type.
• Mocking objects with multiple interfaces. In some tests, where there are several dependencies between classes of different types, you must create many mock objects of different classes. In such situations, it is tedious to manually code many mock objects. Mocking frameworks can help by automatically generating the objects from the interfaces that you specify.
In each unit test, you are interested in a small and specific area of functionality. Some properties and methods of an interface will be crucial to your test, while others will be irrelevant. A mocking framework enables you to specify irrelevant properties and methods in a given test. When the framework creates a mock object for your test, it creates stubs for the irrelevant properties and methods. A stub is a simple implementation with little code. In this way, the mocking framework frees you from having to implement all the requirements of the interface laboriously.
Lesson 2: Implementing an Exception handling Strategy
Unexpected events are likely to occur from time to time in any complex system, including MVC web applications. Occasionally, such unexpected run-time events cause an error. When this happens, ASP.NET or the .NET Framework generates an exception, which is an object that you can use to diagnose and resolve the error. The exception contains information that you can use to diagnose the problem. Exceptions that are not handled in your code will cause the web application to halt and an error message to be displayed to the user.
Raising and Catching Exceptions
An error is an unexpected run-time event that prevents an application from completing an operation. When a line of code causes an error, ASP.NET or the common language runtime creates an exception. This exception is an object of a class that inherits from the System.Exception base class. There are many exception classes. Often the object class identifies what went wrong.
Unhandled Exceptions
When an exception is not explicitly handled by an application, the application stops and the user sees an error message. In ASP.NET MVC applications, this error message is in the form of a webpage. You can override ASP.NET default error pages to display your own error information to users.
Catching Errors with Try/Catch Blocks
In MVC controllers, there are two methods to catch exceptions—the OnException method and the [HandleError] annotation.
Catching Controller Exceptions in OnException
The OnException method is defined on the base Controller class, so you can override it in any MVC controller. When you override the OnException method in a custom controller, MVC runs the method whenever an exception arises and is not handled in a try/catch block. Using this approach, you can handle errors anywhere in your controller without adding many try/catch blocks throughout the code.
In the OnException method, you can catch specific types of exceptions by checking the ExceptionContext.Exception property. Your code must set the context.Result property to display a view to the user. If you do not set this property, the browser displays a blank webpage to the user.
Catching Controller Exceptions with HandleError
Using the [HandleError] annotation, you can use an attribute on individual action methods or on the controller class itself, in which case, the [HandleError] annotation catches errors in any action. When you use the [HandleError] annotation without properties, all exceptions are caught and sent to an MVC view called Error.cshtml. This default error view should be created in the /View/Shared folder.
You can use two properties to control the behavior of [HandleError]:
• ExceptionType. By default, the [HandleError] annotation catches all exceptions. If you set a more specific type with the ExceptionType property, only exceptions of that specific type will be caught.
• View. By default, the [HandleError] annotation forwards users to the Error.cshtml view. You can specify another view file by using the View property. By setting both the ExceptionType and View properties, you can divert exceptions of specific types to views designed specifically to display them.
Configuring Exception Handling
ASP.NET applications display a default error page to users when an unhandled exception occurs in your MVC web application. There are two reasons why you may want to change the default error page:
• You want to display a branded and styled error page that has the same layout as other pages in the application and includes the company logo.
• You want to avoid drawing attention to the technology that powers the site. By letting malicious users know that your site runs ASP.NET MVC, you may encourage them to attack it by using methods that have worked in the past.
To configure a custom error page for your application, use the top-level Web.config file. The custom error page will be displayed when an exception in not handled by any try/catch block or [HandleError] attribute.
Custom Error Modes
To configure custom errors, add the <customErrors> element to the Web.config file. This element must be a child of the <system.web> element. Use the following attributes:
• mode: The mode attribute can be set to one of three values:
o Off: Unhandled errors are displayed on the default ASP.NET error page.
o On: Unhandled errors are displayed in the page you specify in the defaultRedirect attribute.
o RemoteOnly: In this mode, unhandled errors are displayed differently for browsers on remote computers and browsers on the web server. In a production site, all browsers are remote and errors are displayed on the page that you specify in the defaultRedirect attribute. In development situations, the developer often browses to the site on the local computer. When an error occurs, the developer is directed to the default ASP.NET error page, which includes debugging information such as the stack trace. Use the RemoteOnly mode on development computers.
• defaultRedirect: This attribute sets the name of the view that will be used to display unhandled exceptions. When you create this view, place it in the Views/Shared folder.
example:
<system.web>
<customErrors mode="On" defaultRedirect="CustomError" />
</system.web>
HTTP error pages
Some Hypertext Transfer Protocol-level (HTTP) errors cannot be caught by custom MVC error views as specified in Web.config or the [HandleError] annotation. For such errors, you can use the <error> element in Web.config, as a child element of the <customErrors> element.
Logging Exceptions
Writing Error Logging Code
Before you write code to log exceptions in your web application, consider where exceptions should be recorded. Generally, web applications log exceptions to an Extensible Markup Language (XML) file. This approach can be efficient, especially if the text file is kept on a separate drive from the database of the web application and other critical, commonly accessed files. However, the file size of the XML files can grow large, making them difficult to analyze.
A common approach is to log errors to tables in a database. These tables can be a part of a single web application database, or you can place them in a dedicated database away from product catalogs, user profiles, and other information. By logging exceptions to a database, you create a list of exceptions that can be easily searched and analyzed. You can also build a webpage to present these logged exceptions to administrators so that they can access the details from a browser.
You should also consider sending email messages or other types of messages to administrators and developers when exceptions occur. This approach ensures that administrators and developers hear of an error very quickly. It does not require them to review the exceptions logged in the database. Frequently, error handling code in live applications both logs to a database and send email messages to administrators and developers.
Where to Write Error Logging Code
When you decide where to write code that logs errors, you should consider that errors might arise in almost any part of your application. You should choose an approach that enables you to write error logging code once that will run for any exception anywhere in your application.
A more effective approach is as follows:
• Create a custom base controller class for your web application. This class inherits from the System.Web.Mvc.Controller base class.
• In your custom base controller class, override the OnException() method. Place you error logging code in this method.
• When you create controllers, inherit from your custom base controller class, instead of System.Web.Mvc.Controller.
In this way, you can write error logging code only once in the overridden OnExcpetion() method. This catches exceptions from any of the inheriting controllers.
Using Third-Party Logging Tools
Module 7: Structuring ASP.NET MVC 5 Web Applications
Lesson 1: Analyzing Information Structure
What Is Information Architecture?
Planning a Logical Hierarchy
Presenting a Hierarchy in Navigation Controls
The information architecture you design should be presented on webpages in the form of navigation controls. Common approaches to such controls include:
• Site Menus. Most websites have a main menu that presents the main areas of content. For simple web applications, the main menu may include a small number of static links. For larger web applications, when users click a site menu link, a submenu appears.
• Tree Views. A tree view is a menu that shows several levels of information hierarchy. Usually, users can expand or collapse objects at each level, to locate the content they require. Tree views are useful for presenting complex hierarchies in navigable structures.
• Breadcrumb Trails. A breadcrumb trail is a navigation control that shows the user where they are in the web application. Usually a breadcrumb trail shows the current pages and all the parent pages in the hierarchy, with the home page as the top level. Breadcrumb trails enable you to understand how a page fits in with the information architecture shown in menus and tree views.
Presenting a Hierarchy in URLs
You can increase the usability of your web application by reflecting the information architecture in the URLs, which the users see in the Address bar of the web browser. In many web applications, URLs often include long and inscrutable information such as Globally Unique Identifiers (GUIDs) and long query strings with many parameters. Such URLs prevent users from manually formulating the address to an item, and these URLs are difficult to link to a page on your web application. Instead, URLs can be plain and comprehensible, to help users browse through your content.
You can control the URLs that your ASP.NET web application uses, by configuring the ASP.NET routing engine.
What Is Search Engine Optimization?
SEO Best Practices:
• Ensure that each webpage in your web application has a meaningful <title> element in the <head> section of the HTML.
• Ensure that you include a <meta name="keywords"> tag in the <head> element of each page. The content attribute of this element should include keywords that describe the content of the page accurately.
• Ensure that you include a <meta name="description"> tag in the <head> element of each page. The content attribute of this element should include a sentence that describes the content of the page accurately.
• Ensure that the <title> element and the <meta> elements are different for each page in your web application.
• Choose a domain name that includes one or more of your most important keywords.
• Ensure that keywords appear in the <h1>, <h2>, or <h3> elements of your webpage.
• Ensure that navigation controls enable web bots to crawl your entire web application. For example, you may have content in your site that users can only find with the search tool, not by clicking through links. As web bots cannot use search tools, this content will not be indexed.
• Ensure that URLs do not include GUIDs or long query text.
SEO and Web Application Structure
Lesson 2: Configuring Routes
ASP.NET enables developers to control the URLs that a web application uses, to link the URLs and the content by configuring routes. A route is an object that parses a requested URL, and it determines the controller and action to which the request must be forwarded. Such routes are called incoming routes. HTML helpers also use routes when they formulate links to controllers and actions. Such routes are called outgoing routes.
The ASP.NET Routing Engine
Routing governs the way URLs are formulated and how they correspond to controllers and actions. Routing does not operate on the protocol, server, domain, or port number of a URL, but only on the directories and file name in the relative URL.
In ASP.NET, routes are used for two purposes:
• To parse the URLs requested by browsers. This analysis ensures that requests are forwarded to the right controllers and actions. These are called incoming URLs.
• To formulate URLs in webpage links and other elements. When you use helpers such as Html.ActionLink() and Url.Action() in MVC views, the helpers construct URLs according to the routes in the routing table. These are called outgoing URLs.
The Default Route
The default route is simple but logical and works well in many web applications. The default route examines the first three segments of the URL. Each segment is delimited by a forward slash:
• The first segment is interpreted as the name of the controller. The routing engine forwards the request to this controller. If a first segment is not specified, the default route forwards the request to a controller called Home.
• The second segment is interpreted as the name of the action. The routing engine forwards the request to this action. If a second segment is not specified, the default route forwards the request to a controller called Index.
• The third segment is interpreted as an ID value, which is passed to the action as a parameter. The parameter is optional, so if a third segment is not specified, no default value is passed to the action.
example:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Custom Routes
Developers add their own custom routes to a web application for two main reasons:
• To make URLs easier for site visitors to understand.
• To improve search engine rankings.
o User-friendly URLs are therefore a critical tool in SEO.
Controller Factories and Routes
MVC uses controller factories that help create an instance of a controller class to handle a request. MVC uses action invokers to call the right action and pass parameters to that action method. Both controller factories and action invokers refer to the routing table to complete their tasks. The following are steps that MVC conducts when a request is received from a web browser:
1. An MvcHandler object creates a controller factory. The controller factory is the object that instantiates a controller to respond to the request.
2. The controller factory consults the routing table to determine the right Controller class to use.
3. The controller factory creates a Controller object, and the MvcHandler calls the Execute method in that controller.
4. The ControllerActionInvoker examines the request URL and consults the routing table to determine the action in the Controller object to call.
5. The ControllerActionInvoker uses a model binder to determine the values that should be passed to the action as parameters. The model binder consults the routing table to determine if any segments of the URL should be passed as parameters. The model binder can also pass parameters from a posted form, from the URL query text, or from uploaded files.
6. The ControllerActionInvoker runs the action. Often, the action creates a new instance of a model class, perhaps by querying the database with the parameters that the invoker passed to it. This model object is passed to a view, to display results to the user.
As you can see, you can use routes to manage the behavior of controller factories, action invokers, and model binders, because all these objects refer to the routing table. MVC is highly extensible; therefore, developers can create custom implementations of controller factories, action invokers, and model binders. However, by using routes, you can usually implement the URL functionality that you need with the default implementations of these classes. You should ensure that routes cannot implement your required functionality before you plan to customize controller factories, action invokers, or model binders.
Adding and Configuring Routes
Every MVC web application has a RouteTable object in which routes are stored, in the Routes properties. You can add routes to the Routes property by calling the MapRoute() method.
In the Visual Studio project templates for MVC 5, a dedicated RouteConfig.cs code file exists in the App_Start folder. This file includes the RouteConfig.RegisterRoutes() static method where the default route is added to the RouteTable object. You can add custom routes in this method. The Global.asax.cs file includes a call to RouteConfig.RegisterRoutes() in the Application_Start() method, which means that routes are added to the routing table whenever the MVC application starts.
Properties of a Route:
• Name. This string property assigns a name to a route. It is not involved in matching or request forwarding.
• URL. This string property is a URL pattern that is compared to a request, to determine if the route should be used. You can use segment variables to match a part of the URL. You can specify a segment variable by using braces. For example, if you specify the URL, “photo/{title}”, the route matches any request where the relative URL starts with the string, “photo/”, and includes one more segment. The segment variable is “title” and can be used elsewhere in the route.
• Constraints. Sometimes you must place extra constraints on the route to ensure that it matches only with the appropriate requests. For example, if you want relative URLs in the form, “photo/34”, to specify a photo with the ID “34”, you must use a URL property like “photo/{id}”. However, observe that this URL pattern also matches the relative URL, “photo/create”, because it has one extra segment. For IDs, you must constrain the URL to match only segments comprising digits. You can do this by adding a constraint to the route. The Constraints property enables you to specify a regular expression for each segment variable. The route will match a request only if all the segment variables match the regular expressions that you specify.
• Defaults. This string property can assign default values to the segment variables in the URL pattern. Default values are used for segment variables when the request does not specify them.
The Default Route Code
Creating Custom Routes
example:
routes.MapRoute(
name: "PhotoRoute",
url: "photo/{id}",
defaults: new { controller = "Photo", action = "Details" },
constraints: new { id = "[0-9]+" }
);
Precedence of Routes
Routes are evaluated by the routing engine in the order with which they are added to the RouteTable.Routes collection. If a route matches, the routing engine uses it and does not evaluate any later route in the collection. If a route does not match, the routing engine ignores it and evaluates the next route in the collection. For this reason, you must add routes to the RouteTable.Routes collection in the appropriate order. You can add the most specific routes first, such as routes that have no segment variables and no default values. Routes with constraints should be added before routes without constraints.
The route named "Default" matches any request, including those with no relative URL. This default route should be the last that you add to the RouteTable.Routes collection. If the routing engine evaluates this route, the route is always used. Any routes added after the “Default” route are never used.
Using Routes to Pass Parameters
The routing engine separates the relative URL in a request into one or more segments. Each forward slash delimits one segment from the next. If you want one of the segments to specify the controller name, you can use the {controller} segment variable. The controller factory always interprets this variable as the controller to instantiate. Alternatively, to fix a route to a single controller, you can specify a value for the controller variable in the defaults property. In a similar manner, if you want one of the segments to specify the action method, you can use the {action} segment variable. The action invoker always interprets this variable as the action to call. Alternatively, to fix a route to a single action, you can specify a value for the action variable in the defaults property.
Segment variables or default values with other names have no special meaning to MVC and are passed to actions. You can access the values of these variables by using one of two methods: the RouteData.Values collection or by using model binding to pass values to action parameters.
The RouteData.Values Collection
Using Model Binding to Obtain Parameters
The default MVC action invoker is a class named, ControllerActionInvoker. This invoker uses a class named, DefaultModelBinder, to pass the appropriate parameters to actions. This model binder uses the following logic to pass parameters:
1. The binder examines the definition of the action to which it must pass parameters. In the example, the binder determines that the action requires an integer parameter called, PhotoID.
2. The binder searches for values in the request, which can be passed as parameters by name. In the example, the binder searches for integers because the action requires integers. The binder searches for values in the following locations in sequential order:
a. Form Values. If the user fills out a form and clicks the Submit button, the binder can find parameters in the Request.Form collection.
b.Route Values. If the matched route includes the segment variable {photoid}, the binder can find the value for the PhotoID parameter in the RouteData.Values collection. This match is case-insensitive.
c. Query Strings. If the user request includes named parameters after a question mark, the binder can find these parameters in the Request.QueryString collection.
d. Files: If the user request includes uploaded files, these files can be used as parameters in an action. File parameters in actions must use the HttpPostedFileBase type.
Optional Parameters
example:
routes.MapRoute(
name: "ProductRoute",
url: "product/{id}/{color}",
defaults: new { color = UrlParameter.Optional }
);
Unit Tests and Routes
Creating a HTTP Context Test Double
In a webpage request, ASP.NET stores details of the request in an HTTP Context object. These details include the URL that was requested, details of the browser, and other information. To write a unit test for routes, you must simulate the HTTP Context object by creating a test double class.
example: FakeHttpContextForRouting + FakeHttpRequestForRouting + FakeHttpResponseForRouting
Writing Routing Tests
After creating an HTTP context test double, you can write unit tests for each route in the routing table. These unit tests adopt the following general phases:
• Arrange. In the Arrange phase of the test, you can create a new HTTP context from your test double class. You can set the request URL for this object to be the URL you want to test. You can then create a new route collection and call the RouteConfig.RegisterRoutes() method in your web application.
• Act. In the Act phase, you can test the routes by calling the GetRouteData() method of the route collection. You can then pass the fake HTTP context to this method.
• Assert. In the Assert phase, you can use the RouteData.Values collection to check that the controller, action and other values are assigned correctly.
Lesson 3: Creating a Navigation Structure
The Importance of Well-Designed Navigation
The information architecture you design for your web application is a logical hierarchy of objects. This hierarchy should be clear and understandable to the audience of your web application. If your web application is designed for people with specialist knowledge, you can implement information architecture that requires specialist knowledge.
You should ensure two things with these navigation controls:
• An obvious next step.
• A clear context.
Common Types of Navigation Controls:
• Top menus. Often placed at the top of the page or immediately beneath the application branding, top menus link to the main areas of your web application. In some applications, each item in the top menu has a submenu with links to lower level items and pages.
• Tree views. A tree view is a hierarchical menu that can display many items in multiple levels in your web application. By default, a tree view often displays only one or two levels of the information architecture. Users can expand lower levels to find the content they need. Tree views enable users to explore multiple levels on a single page. Tree views can also show clearly the position of the current page, in the hierarchy.
• Breadcrumb trails. Often presented as a horizontal sequence of links across the top of a webpage, a breadcrumb trail shows the current page and its parents in all the higher levels of the hierarchy. Breadcrumb trails show the current position of the user, in the context of the web application and enable users to navigate to higher, less specific pages.
• Footer menus. The page footer is often not visible when a user arrives on a page. The user must scroll to the end of the page to see the footer. The footer is often used as a location for important, but not business-critical, links. For example, links to copyright and other legal information, links to parent companies, and links to site maps are often placed in the footer menu.
The MVC Site Map Provider
A site map provider is an ASP.NET component that stores the logical hierarchy of your web application. Navigation controls such as top menus, tree views, and breadcrumb trails can take their links from this single hierarchy.
The MVC Site Map Provider is a provider designed to work with MVC controllers and actions. It presents the information architecture that you can configure in a simple XML file. This hierarchy is completely independent of the model, controllers, and actions in your applications, although you can build links to them. The provider also includes HTML helpers, which you can use in views to render menus, tree views, and breadcrumb trails.
Configuring the MVC Site Map Provider
Configuring the MVC Site Map Provider in Web.Config
Creating the Site Map File
Adding Menu Controls
Module 8: Applying Styles to ASP.NET MVC 5 Web Applications
Lesson 1: Using Layouts
What are layouts?
Layouts are also called template views. Layouts enable you to define a common style template, and then apply it to all the views in a web application. The functionality of layouts is similar to that of the master page in a traditional ASP.NET web application. You can use layouts to define the content layout or logic that is shared across views.
You can define multiple layouts in an ASP.NET MVC 5 application, and each layout can have multiple sections. You can define these sections anywhere in the layout file, even in the <head> section of the HTML. Sections enable you to output dynamic content to multiple, non-contiguous, regions of the final response.
Creating a Layout
store layout files in \Views\Shared folder
@RenderBody() in layout file is used to render content of a child view:
• any content that is not in a @section will be rendered by RenderBody
@RenderSection() in layout file is used to render content that is different from RenderBody():
• designate content to be rendered at RenderSection() using a @section declaration
• by default, Sections are required, meaning each child view must define the section
• pass required: false to designate that the section is optional
Linking Views and Layouts
_ViewStart.cshtml runs before all the other views in the web application:
• primary purpose of _ViewStart is to set values that all the other views will have to use
• ViewBag can be used to pass information between view and layout
• ViewStart links layout file
Lesson 2: Applying CSS Styles to an MVC Application
Importing Styles into an MVC Web Application
use CSS to style web application (external CSS file, inline CSS, and CSS code block in HTML):
• <link href="~/Views/Shared/StyleSheet1.css" rel="stylesheet" type="text/css" />
CSS class selector:
.menu
{
font-weight:bold;
}
<p class="menu">some menu</p>
CSS id selector:
#menu
{
font-size:16px;
}
<p id="menu">some menu</p>
Lesson 3: Creating an Adaptive User Interface
The HTML5 Viewport Attribute
use viewport attribute for adaptive rendering:
• customize web application to display differently, based on the capabilities of web browser or device
• <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
• device-width, device-height, initial-scale, minimum-scale, maximum-scale, user-scalable
CSS Media Queries
use CSS Media Queries to allow conditional application of CSS styles, based on the device conditions or browser capabilities:
@media only screen and (max-width: 500px) {
header{
float: none;
}
}
<link rel="stylesheet" type="text/css" href="smallscreen.css" media="only screen and (max-width: 500px)" />
MVC 5 Templates and Mobile-Specific Views
ASP.NET MVC 5 web application analyses the request for views with the naming convention [view].mobile.cshtml when received from a mobile browser
check UserAgent string to create custom devive / browser specific views
Module 9: Building Responsive Pages in ASP.NET MVC 5 Web Applications
Lesson 1: Using AJAX and Partial Page Updates
While developing web applications, to update individual sections in the page, you may need to reload the entire webpage. Asynchronous JavaScript and XML (AJAX) in ASP.NET MVC 5 enables partial page updates, to help update sections of a webpage, without reloading the entire page. The Ajax.ActionLink helper helps implement partial page updates in your web application.
Why Use Partial Page Updates?
ASP.NET and MVC facilitate server-side processing. Server-side processing enables HTML rendering to occur at the server side and the server usually generates the HTML. When you update a webpage, any updates or actions performed on the page require a round-trip request to the server. Such constant server requests affect the performance of the application.
The AJAX development model helps reduce the need for refreshing an entire webpage, each time an update of page content is required. AJAX uses JavaScript and XML to obtain information from the client system. AJAX creates webpages based on the XML information downloaded from the server. However, developing web applications by using AJAX is not easy, because it requires using complex technologies, such as JavaScript and XML. Microsoft includes a feature in ASP.NET called partial page updates that functions along with AJAX to reduce the need for refreshing an entire webpage, each time an update occurs.
Partial page updates use AJAX technologies to help update individual sections of a webpage, during postback. Partial page updates:
• Require fewer lines of code.
• Help reduce the data sent to users, each time a webpage update occurs.
• Increase the responsiveness of the web application.
Using AJAX in an MVC 5 Web Application
To implement AJAX in your MVC 5 application, you need to create views that render only the updated content, and not the entire webpage. You can initially develop your web application without using AJAX, and then check the application for any functionality errors. This practice helps reduce the time required to troubleshoot the application. This practice also helps separate any application functionality errors from errors that occur while implementing AJAX.
To implement partial page updates, you need to create a view, called a partial view, which includes only the section that you need to update.
With AJAX, the Javascript retrieves only a specific portion of a webpage, which you want to update, from the server. In the ViewController class, you need to update the View function to return the PartialView class, instead of the entire View class.
The Ajax.ActionLink Helper
You can use the Ajax.ActionLink helper to trigger partial page updates. The Ajax.ActionLink helper helps initiate the Javascript, to obtain the updated HTML information from the view and replace or insert the updated HTML information at a specific location.
example:
<div id="divMessage">@ViewBag.Message</div>
@Ajax.ActionLink("Refresh","HelloWorld", new AjaxOptions{ HttpMethod = "POST", UpdateTargetId = "divMessage", InsertionMode = InsertionMode.Replace })
HttpMethod: Obtain the HTML information from the HelloWorld view, by using the HTTP POST method.
UpdateTargetId: Replace the content in the divMessage HTML element.
While using the Ajax.ActionLink helper, you need to include the jQuery and jQuery unobtrusive libraries in the same webpage, because the Ajax.ActionLink helper uses scripts from these two libraries.
Lesson 2: Implementing a Caching Strategy
Why Use Caching?
Caching involves storing the information that is obtained from a database in the memory of a web server. If the content rendered by a webpage is static in nature, the content can be stored in caches or proxy servers. When a user requests content from a web application, caching ensures that the user receives content from the cache, thereby eliminating the need for repeated real-time processing.
Caching:
• Reduces the need to repeatedly retrieve the same information from the database.
• Reduces the need to reprocess data, if a user places a request multiple times.
• Helps improve the performance of a web application, by reducing the load on servers.
• Helps increase the number of users who can access the server farm.
However, caching does not help web applications that include frequent content changes. This is because, the content rendered from a cache may be outdated, when compared to the current information. Therefore, you should evaluate the content of your web application and analyze the impact of rendering outdated content, before implementing caching.
The Output Cache
Output cache allows ASP.NET engines to store the rendered content of a webpage in the memory of the web server. Therefore, when a user requests a specific page multiple times, the content is retrieved from the cache, thereby avoiding the execution of programming code in the server.
Output cache is a good complement to AJAX partial page updates. Output cache and partial page updates reduce the workload on the server and increase the number of user requests that a server can handle.
In ASP.NET MVC 5, you can implement output caching, by adding the OutputCache attribute to the controller.
The OutputCache attribute helps direct the rendering engine to the cache that contains results from the previous rendering process. The Duration parameter of the OutputCache attribute helps control the period of time in seconds for which data should be stored in the cache.
By default, the output cache stores only one copy of the rendered content, for each view. Consider a view with the QueryString input parameter that enables content to change based on the variable gathered from the database or a prior request. In this case, you can add the VaryByParam property to the OutputCache attribute, to store a copy of each unique combination of parameters in the cache.
VaryByParam property refers to QueryString, instead of other MVC parameters. You can also use the VaryByCustom property.
If you want to control and implement your own logic to determine when a new copy should be stored, you need to override the GetVaryByCustomString function in the Global.asax file of your project.
The Data Cache
Web applications usually depend on the content in a database, to render content on a webpage. Databases sometimes encounter performance issues caused by poorly written queries, which can slow down the performance of database requests resulting in poor webpage performance. You can implement the data cache in your web application to avoid loading data from a database every time a user places a request. The MemoryCache class allows you to implement data cache in your web application.
Implementing the data cache involves the following actions:
1. Loading information from the database
2. Storing content in the MemoryCache object
3. Retrieving data from the MemoryCache object
4. Ensuring that content is available in the MemoryCache object; otherwise, reloading the content
example:
System.Data.DataTable dtCustomer = System.Runtime.Caching.MemoryCache.Default.AddOrGetExisting("CustomerData", this.GetCustomerData(), System.DateTime.Now.AddHours(1));
• Key. The unique identifier of the object that should be stored in the memory cache.
• Value. The object that should be stored in the memory cache.
• AbsoluteExpiration. The time when the cache should expire.
The HTTP Cache
The Browser Cache
Most web browsers store the content downloaded from web servers in their local cache. Storing data in the local cache helps remove the need to repeatedly download content from the server. Web browsers frequently check content for updates. If the content is updated in the server, web browsers download the content from the server, to attend to user requests. Otherwise, web browsers render content from the local cache.
The Proxy Cache
The functionality of the proxy cache is similar to the functionality of the browser cache. However, the cache is stored on a centralized server. Users can connect to the Internet or web servers by using this proxy server. Proxy servers store a copy of a web application in a manner similar to a web browser storing a copy of an application in the local drives. Many users can access the cache in a proxy server, while only one user can access the browser cache at a time.
Preventing Caching
Caching can sometimes create issues in web applications, because if an application involves frequent content updates, caching prevents users from viewing these content updates. To resolve caching issues, you can implement an HTTP header called Cache-Control. The Cache-Control header indicates to the web browser how to handle the local cache. All HTTP clients, such as browsers and proxy servers, respond to the instructions provided in the Cache-Control header to determine how to handle the local cache of a web application.
HttpCachePolicy.SetCacheability:
Sets the Cache-Control HTTP header. The Cache-Control HTTP header controls how documents are to be cached on the network.
NoCache Sets the Cache-Control: no-cache header. Without a field name, the directive applies to the entire request and a shared (proxy server) cache must force a successful revalidation with the origin Web server before satisfying the request. With a field name, the directive applies only to the named field; the rest of the response may be supplied from a shared cache.
Private Default value. Sets Cache-Control: private to specify that the response is cacheable only on the client and not by shared (proxy server) caches.
Public Sets Cache-Control: public to specify that the response is cacheable by clients and shared (proxy) caches.
Server Specifies that the response is cached only at the origin server. Similar to the NoCache option. Clients receive a Cache-Control: no-cache directive but the document is cached on the origin server. Equivalent to ServerAndNoCache.
ServerAndNoCache Applies the settings of both Server and NoCache to indicate that the content is cached at the server but all others are explicitly denied the ability to cache the response.
ServerAndPrivate Indicates that the response is cached at the server and at the client but nowhere else. Proxy servers are not allowed to cache the response.
Module 10: Using JavaScript and jQuery for Responsive MVC 5 Web Applications
Lesson 1: Rendering and Executing JavaScript Code
Adding JavaScript Files
You can add JavaScript code to web applications by:
• Adding the JavaScript code to HTML.
• Defining the JavaScript code in dedicated JavaScript files.
example: <script src="~/Scripts/JavaScript1.js" type="text/javascript"></script>
Calling JavaScript Procedures
use JavaScript event to trigger JavaScript functions
JavaScript Libraries
JavaScript libraries help to:
• Reduce the amount of code you need to write to add functions.
• Reduce the time the system takes to debug the application.
Using Content Delivery Networks for JavaScript Libraries
A content delivery network (CDN) is a group of geographically distributed servers used for hosting contents for web applications. In many cases, you can bring web content geographically closer to your applications users by using a CDN to host libraries. This will also improve the scalability and robustness of the delivery of that content.
example: <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-3.2.1.js" type="text/javascript"></script>
Using the NuGet Tool to Add Packages
Lesson 2: Using jQuery and jQueryUI
jQuery is a JavaScript library that simplifies the adding of JavaScript to HTML pages.
Introduction to jQuery
jQuery includes the following features:
• DOM element selections
• DOM traversal and modification
• DOM manipulation, based on CSS selectors
• Events
• Effects and animations
• AJAX
• Extensibility through plug-ins
• Utilities
• Compatibility methods
• Multi-browser support
The jQuery family includes the following two companion modules:
• jQuery UI. This library adds functions and other supporting elements that help implement a rich interface to HTML-based applications.
• jQuery mobile. This library adds functions that optimize the application interface for mobile devices.
Linking to jQuery Libraries
jQuery Original Version and jQuery Minified Version provide similar functionalities; however, they optimize web applications for different purposes:
• jQuery Original Version (jQuery-<version>.js). This is the uncompressed version of the jQuery library.
• jQuery Minified Version (jQuery-<version>.min.js). This includes the compressed and gZip versions of jQuery.
Bundling and Minification
Bundling is a feature in ASP.NET that you can use in MVC 5 web applications. Bundling helps combine multiple JavaScript libraries into a single HTTP request.
Minification compresses code files before incorporating them in the client application. Bundling and minification help reduce the loading time of web applications by reducing both the number and size of HTTP requests.
To use bundling and minification in your web application, you should perform the following steps:
1. Reference the Microsoft.AspNet.Web.Optimization library in your application by using NuGet packages.
2. In the App_Start folder of your project, add the BundleConfig.cs file
3. In the BundleConfig.cs file, add the following code:
public static void RegisterBundles(System.Web.Optimization.BundleCollection bundles)
{
bundles.Add(new System.Web.Optimization.ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js","~/Scripts/JavaScript1.js"));
}
4. In the Global.asax Application_Start event, add the following code:
BundleConfig.RegisterBundles(System.Web.Optimization.BundleTable.Bundles);
The ScriptBundle class enables you to define the bundle that helps combine multiple JavaScript libraries into a single file. You can use a special placeholder, such as {version} in the JavaScript path, to help update the version of jQuery libraries. ASP.NET replaces {version} with the latest version number of the JavaScript libraries present in the Scripts folder. If the minified version of jQuery is available in the Scripts folder, the MVC 5 engine selects the minified version for bundling. Then, in your View file, you can include the following lines of code to render the bundled JavaScript file.
example:
<head>
@Scripts.Render("~/bundles/jquery")
</head>
You should add the following line of code in a page or namespace of the Web.config file in the View folder. This code helps trigger the functioning of @Scripts.Render.
example:
<add namespace="System.Web.Optimization"/>
Based on the compilation setting in the Web.config file, the jQuery library renders minified versions of Javascript. For example, the following code sets the debug attribute of the compilation element to false, which allows jQuery to use the non-minified version of the libraries, making debugging of the libraries easier.
example: <compilation debug="false" />
Accessing HTML Elements by Using jQuery
jQuery helps access HTML elements, to create interactive web applications. You use the following selector to select elements by element name, id, or CSS class, while adding jQuery code to access HTML elements:
$(element name|#id|.class)
example: $(“#HelloButton”) // jQuery selector accesses the HTML element with the HelloButton ID
You can use jQuery to access or modify all instances of a specific HTML element, in an HTML page
$(“a”) // Query selector identifies all instances of the A element in an HTML page
After accessing the HTML elements, you can perform actions on the elements, such as:
• Modifying the attributes on the HTML elements.
• Defining event handlers to respond to events associated with the selected HTML elements.
If the jQuery scripts load before the webpage loads, you may encounter errors such as object not defined. You can place the jQuery code in the document.ready event, to prevent the code from loading until all HTML elements in the page load.
example:
<body>
<div>
Hello
<input type="button" value="Hello" id="HelloButton" />
</div>