Realizacja aplikacji internetowych
Download
Report
Transcript Realizacja aplikacji internetowych
Realizacja aplikacji
internetowych
MVC
ASP.NET
Architektura aplikacji
oparta na pojęciach
Strony
Sesji
oraz aplikacji
Strony definiowane są
jako:
mark-up
ASP
kod w CS/VB tzw "code
behind"
ASP.Net z IIS < 7
ASP.NET
Więcej na
http://www.west-wind.com/presentations/howaspnetworks/howaspnetworks.asp
ASP.NET <7.0
Więcej na
http://www.west-wind.com/presentations/howaspnetworks/howaspnetworks.asp
ASP.Net z IIS >=7
Więcej na
http://www.west-wind.com/presentations/howaspnetworks/howaspnetworks.asp
http://www.iis.net/learn/application-frameworks/building-and-running-aspnetapplications/aspnet-integration-with-iis
Cykl życia strony ASP.Net
ASP.NET modularyzacja/reużycie
kodu
Master Page
Kontrolki ascx
Nawigacja
SiteMap
SiteMapProvider
Kontrolki
Filtrowanie (w
zależności od ról)
Lokalizacja
Nawigacja
SiteMap
SiteMapProvider
Kontrolki
Filtrowanie (w
zależności od ról)
Lokalizacja
ASP.NET Wady
Skomplikowany model życia strony - inicjalizacja
kontrolek itd.
Nieoczywiste i poważne następstwa wykorzystania
metafory aplikacji stanowej (ViewState).
Efekt: niewydolne i nieinteraktywne aplikacje. Bariera dla
doświadczonych deweloperów WWW.
Sztuczna komunikacji m. stronami (->sesja, aplikacja,
baza). Tendencja do komplkacji kodu.
Brak kontroli nad kodem emitowanym przez kontrolki
(lepiej w 4.0) oraz trudność tworzenia/rozbudowy kotrolek
Fałszywe poczucie separacji logiki i wyglądu
Słaba testowalność
Co to jest ViewState
Pole __VIEWSTATE
typu StateBag klasy System.Web.UI.Control
(dziedziczą z niej wszystkie kontrolki (w tym
instancje klasy System.Web.UI.Page czyli strony)
w ASP.NET każde odwołanie do strony powoduje
utworzenie jej nowej instancji. ViewState
przechowuje stan każdej kontrolki na stronie.
Megabajty danych …
ASP.NET Co z tym można zrobić?
AJAX Control Toolkit :
Dodatkow
infrastruktura (script manager)
Dynamiki uzyskana przez proste w użyciu kontrolki
serwerowe (UpdatePanel itd.)
Kontrolki wizualne emitujące kod w JavaScript
pozwalający na asynchroniczną komukację z (no
wlasnie z czym?) na serwerze
Jeszcze trudniejsze staje się:
roszerzanie/dodawanie
kontrolek
panowanie nad kodem HTML (CSS)
opanowanie zachowania skomplikowanej aplikacji
ASP.NET Co z tym można zrobić?
WCSF – wprowadzenie usystematyzowanej
architektury – wariacji na temat.
Model+Prezenter+Widok
Zalecenia
+ wizardy do generowania klasy prezentera
ASP pozostaje tylko ASP – w tym swiecie to widok
"wybiera sobie" prezenter
Pewna dodatkowa komplikacja infrastruktury
(bootstapery itd.)
Dlaczego MVC…
MVC ułatwia zapanowanie nad złożonością aplikacji dzięki podziałowi na
funkcjonalne komponenty.
MVC pozwala oderwać się od skomplikoqwanego modelu życia form ASP,
ViewState-u itd. Dzięki temu developerzy mogą łatwiej w pełni kontrolować
zachowanie aplikacji.
Front Controller, wzorzec zastosowany dla potrzeb przetwarzania żądań z
przeglądarki wspiera wykorzystanie złożonej architektury aplikacji oraz
wspiera przekierowywanie poleceń.
MVC wspiera dobrze TDD. Wszystkie kontrakty we frameworku bazują na
interfejsach stad moga być łatwo testowane przy użyciu mocków, stubów
itd..
Silna separacja zadań dobrze działa w dużych zespołach pracujacych na
większymi witrynami. W szczególności warto podkreślić oddzielenie logiki
od wyglądu.
URL routing policy, action-method parameter serialization i inne
komponenty. The ASP.NET MVC framework wspiera też DI i kontenery
IOC.
Pojęcia
Model. Obiekty modelu są częścią
aplikacji która implementuje logike
domenową.
Widoki. Widoki sa komponentami
które wyswitlają interfejs
użytkownika (UI).
Kontrolery. Kontrolery są
komponentami, ktore obsługuja
interakcję z użytkownikiem.
Finalnie są odpowiedzialne za
wybór modelu oraz widoku.
Rozluźnienie połączeń między komponentami.
Kluczowe koncepcje …
Routing
Kontrolery
Widoki
+ akcje
Routing
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
// Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" }
// Parameter defaults
);
}
protected void Application_Start() {
RegisterRoutes(RouteTable.Routes);
}
Convention over configuration
public class HomeController : Controller {
public ActionResult Index() {
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
Widok HOME\Index
public ActionResult About() {
return View("CustomAbout");
}
}
Widok HOME\CustomAbout
Widok
Może być zdefiniowany w ASP.NET, Razor lub wielu
innych – w każdym wypadku nie ma tu zednych ukrytych
mechanizmów, zdarzeń, kontrolek itd. Markup po prostu
definiuje wygląd strony lub jej fragmentu.
ASP.NET MVC - Results
Action Result
Helper Method
Description
ViewResult
View
Renders a view as a Web page.
PartialViewResult
PartialView
Renders a partial view, which
defines a section of a view that can
be rendered inside another view.
RedirectResult,
PermantRedirectResult
Redirect
Redirects to another action method
by using its URL.
RedirectToRouteResult
RedirectToAction
Redirects to another action method.
RedirectToRoute
ContentResult
Content
Returns a user-defined content type.
JsonResult
Json
Returns a serialized JSON object.
JavaScriptResult
JavaScript
Returns a script that can be
executed on the client.
FileResult
File
Returns binary output to write to the
response.
EmptyResult
(None)
Represents a return value that is
used if the action method must
return a null result (void).
Widok
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent"
runat="server">
Home Page
</asp:Content>
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent"
runat="server">
<h2><%= Html.Encode(ViewData["Message"]) %></h2>
<p>to<br>
Sample content
</p>
</asp:Content>
Widok silnie typowany
<%@ Page Title="" Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<MvcDataViews.Models.Person>"
%>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent"
runat="server">
Persons
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent"
runat="server">
<p> Id=<%= Html.Encode(Model.Id) %> </p>
<p> Name:<%= Html.Encode(Model.Name) %> </p>
</asp:Content>
Widok silnie typowany
public ActionResult Index()
{
Person item = Repository.GetRecentPerson();
return View("Index", item);
}
Helpery Html
ActionLink — Links to an action method.
BeginForm * — Marks the start of a form and links to the
action method that renders the form.
CheckBox * — Renders a check box.
DropDownList * — Renders a drop-down list.
Hidden — Embeds information in the form that is not
rendered for the user to see.
ListBox — Renders a list box.
Password — Renders a text box for entering a password.
RadioButton * — Renders a radio button.
TextArea — Renders a text area (multi-line text box).
TextBox * — Renders a text box.
Helpery Html
<%@ Control Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<ContactManager.Models.Cont
act>" %>
<p>
<%= Html.LabelFor(c => c.Name) %>:
<%= Html.DisplayFor(c => c.Name) %>
</p>
<p>
<%= Html.LabelFor(c => c.Email) %>:
<%= Html.DisplayFor(c => c.Email) %>
</p>
Helpery Html
<% using(Html.BeginForm("HandleForm", "Home")) %>
<% { %>
<!-- Form content goes here -->
<%= Html.CheckBox("bookType") %>
<%= Html.DropDownList("pets") %>
<% } %>
// w kontrolerze
List<string> petList = new List<string>();
petList.Add("Dog");
petList.Add("Cat");
petList.Add("Hamster");
petList.Add("Parrot");
petList.Add("Gold fish");
ViewData["Pets"] = new SelectList(petList);
Helpery vs silne typowane
MVC 1:
MVC 2:
ASP.NET MVC - helpery
Nowe helpery HTML:
Html.TextBoxFor()
Html.TextAreaFor()
Html.DropDownListFor()
Html.CheckboxFor()
Html.RadioButtonFor()
Html.ListBoxFor()
Html.PasswordFor()
Html.HiddenFor()
Html.LabelFor()
Inne helpery:
Html.EditorFor()
Html.DisplayFor()
Html.DisplayTextFor()
Html.ValidationMessageFor()
Prosty helper do wyprowadzania
wierszy tabeli
widok jest silnie typowany przez IEnumerable<Book>
<% Model.TableRow( (book, lineNo) =>
{ %>
<tr>
<td> <%= Html.Encode(lineNo) %> </td>
<td> <%= Html.Encode(book.Author) %> </td>
<td> <%= Html.Encode(book.Title) %> </td>
<td> <%= Html.Encode(book.Year) %> </td>
</tr>
<% }); %>
naglowek trzeba wygenerowac oddzielnie
Prosty helper - realizacja
public static class MVCHelpers
{
public static void TableRow<T>(this IEnumerable<T> items,
Action<T> action)
{
foreach (T item in items)
action(item);
}
public static void TableRow<T>(this IEnumerable<T> items,
Action<T, int> action)
{
int counter = 0;
foreach (T item in items)
action(item, ++counter);
}
}
Helper – składnia extension methods
public static class LabelExtensions {
public static string Label(this HtmlHelper helper,
string target, string text)
{
return String.Format("<label for='{0}'>{1}</label>",
target, text);
}
}
ASP.NET MVC - Partial view
Widok zdefiniowany w wizardzie jako Partial view
Czesto używana konwencja nazwa zaczyna sie od _
Widok jest typowany tj. używamy wewnątrz @Model
Użycie w kodzie widoku głównego:
...
<%= foreach (var element in Model.elements) { %>
<%=
Html.Partial("_Podwidok", element); %>
<%=} %>
ASP.NET MVC - Walidacja
public class Pals {
[Required()]
[Range(33,99)]
public float Height { get; set; }
[Required()]
[StringLength(7)]
public string Name { get; set; }
[ScaffoldColumn(false)]
public int ID { get; set; }
public bool cool { get; set; }
[DataType(DataType.EmailAddress)]
[RegularExpression(@"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@(.*)$")]
public string email { get; set; }
[DataType(DataType.MultilineText)]
public string Bio { get; set; }
}
MVC – Walidacja serwerowa
public ActionResult Create(Person newPal)
{
if (ModelState.IsValid) {
return Redirect("/");
}
return View("DetailedErrorInfo", newPal);
}
.....
<%= Html.LabelFor( model => model.Height ) %>
<%= Html.TextBoxFor( model => model.Height ) %>
<%= Html.ValidationMessageFor( model => model.Height ) %>
MVC - Walidacja kliencka
<script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.js"
type="text/javascript"></script>
<script src="http://ajax.microsoft.com/ajax/jquery.validate/1.5.5/jquery.validate.js"
type="text/javascript"></script>
<script src="<%= Url.Content("~/Scripts/MicrosoftMvcJqueryValidation.js") %>"
type="text/javascript"></script>
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<MvcSimpObj.Models.Pals>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>EditforModel</h2>
MVC – Walidacja kliencka
<% Html.ClientValidationEnabled = true; %>
<% using (Html.BeginForm()) { %>
<fieldset>
<%= Html.ValidationSummary("Broken stuff:") %>
<%= Html.EditorForModel() %>
<input type="submit" value=" Submit " />
</fieldset>
<% } %>
<% Html.RenderPartial("linksPalsID"); %>
</asp:Content>
MVC – Asynchroniczny kontroler
Żądanie z WWW jest obsługiwane przez jeden z wątków
z puli roboczej serwera
Po zainicjowaniu akcji wątek jest zwalniany
Po ukończeniu akcji obsługa jest wznawiana (przez pot.
Inny) wątek z puli roboczej
MVC – tradycyjny kod
public class PortalController: Controller {
public ActionResult News(string city) {
NewsService newsService = new NewsService();
ViewStringModel headlines =
newsService.GetHeadlines(city);
return View(headlines);
}
}
asynchroniczny kod
public class PortalController : AsyncController {
public void NewsAsync(string city) {
AsyncManager.OutstandingOperations.Increment();
NewsService newsService = new NewsService();
newsService.GetHeadlinesCompleted += (sender, e) => {
AsyncManager.Parameters["headlines"] = e.Value;
AsyncManager.OutstandingOperations.Decrement();
};
newsService.GetHeadlinesAsync(city);
}
public ActionResult NewsCompleted(string[] headlines) {
return View("News", new ViewStringModel {
NewsHeadlines = headlines } );
}
MVC Razor - przykład
Wyrażenia@( .... )
Bloki @{ .... }
Wypisywanie contentu <text></text>
Razor – przykład mark-up ASP
Razor – przykład mark-up ASP
MVC Razor - przykład
MVC Razor - przykład
Atrybuty w MVC
public class HomeController : Controller
{
Typ żądania
[HttpGet]
[ActionName("Lista")]
Alias nazwy akcji
public ActionResult Index() {
return View();
}
[ChildActionOnly]
public ActionResult ChildAction() {
return View();
}
}
ChildActionOnly - ta akcja nie moze byc zawołana z zewnątrz ale wciąż
może być wywołana np. przez redirect lub
<%Html.RenderAction("ChildAction"); %>
Filtry
Koncepcje:
AoP
FrontController
F. Mogą być stosowane
Do
akcji
Do kontrolera
Do aplikacji
Filtry
Typ
Domyślna
implementacja
Dzialanie
Authorization AuthorizeAttribute
Uruchamiany przed innymi
filtrami/akcjami
Action
ActionFilterAttribute
Uruchaminiany przed/po akcji
Result
ResultFilterAttribute
Uruchaminiany przed/po zwrocie
Exception
HandleErrorAttribute
Uruchamiany gdy inny filtr/akcja zrzucą
wyjątek
Deklaratywna autoryzacja w MVC
public class HomeController : Controller
{
public ActionResult About()
{
return View(); }
[Authorize]
public ActionResult AuthenticatedUsers()
{
return View(); }
[Authorize(Roles = "Admin, Super User")]
public ActionResult AdministratorsOnly()
{
return View(); }
[Authorize(Users = "Betty, Johnny")]
public ActionResult SpecificUserOnly()
{
return View(); }
}
Domyślna obsługa błedów
Domyślnie wyświetlana jest ~/Views/Shared/Error
Nie powinna byc dostępna w produkcji!!!
Włączenie obsługi błedów na poziomie konfiguracji
Zróżnicowanie local/remote
Domyślne/konkretne bledy
Włączenie obsługi błedów na poziomie filtrów
Web.config
<customErrors mode="On“ defaultRedirect=“DefaultError”
mode="Remote">
<error statusCode="401" redirect="/Errors/Http401" />
</customErrors>
Rejestracja obsługi błedów
[HandleError]
public class HomeController : Controller {
public ActionResult Index() {
throw new HttpException(401, "Unauthorized");
}
public ActionResult About() { return View(); }
}
Dodanie globalnych filtrów:
public static void RegisterGlobalFilters(
GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
Obsługa wyjątków
[HandleError(ExceptionType=typeof(NullReferenceExceptio
n@Model HandleErrorInfo
…
@{ViewBag.Title = "Sorry, there was a problem!“;}
<p>There was a
<b>@Model.Exception.GetType().Name</b>
while rendering <b>@Model.ControllerName</b>'s
<b>@Model.ActionName</b> action.</p>
<p>The exception message is:
<b><@Model.Exception.Message></b>
</p>
<pre>@Model.Exception.StackTrace</pre>
Własny action filter
public class ActionLogFilterAttribute : ActionFilterAttribute,
IActionFilter {
public override void OnActionExecuting(
ActionExecutingContext filterContext) { ... }
public override void OnActionExecuted...
public override void OnResultExecuting...
public override void OnResultExecuted...
}
Aplikacja filtru:
[ActionLogFilter]
lub
RegisterGlobalFilters -> filters.Add(new
ActionLogFilterAttribute());
public class RequestTimingFilter : IActionFilter, IResultFilter
{
public void OnActionExecuting(ActionExecutingContext filterContext)
{
GetTimer(filterContext, "action").Start();
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
GetTimer(filterContext, "action").Stop();
}
public void OnResultExecuting(ResultExecutingContext filterContext)
{
GetTimer(filterContext, "render").Start();
}
…
}
private static Stopwatch GetTimer(ControllerContext context, string name) {
var key = string.Format("__timer__{0}", name);
if (context.HttpContext.Items.Contains(key)) {
return (Stopwatch)context.HttpContext.Items[key];
}
var result = new Stopwatch();
context.HttpContext.Items[key] = result;
return result;
}
public void OnResultExecuted(ResultExecutedContext filterContext)
{
var renderTimer = GetTimer(filterContext, "render");
renderTimer.Stop();
var actionTimer = GetTimer(filterContext, "action");
var response = filterContext.HttpContext.Response;
if (response.ContentType == "text/html“) {
response.Write( string.Format(
"<div style='font-size: 70%; font-weight: bold; color: \
#888;'>Action '{0} :: {1}'<br /> Execute: {2}ms, Render: \
{3}ms.</div>",
filterContext.RouteData.Values["controller"],
filterContext.RouteData.Values["action"],
actionTimer.ElapsedMilliseconds,
renderTimer.ElapsedMilliseconds
));}
}
Cache
[OutputCache(
Location=OutputCacheLocation.ServerAndClient,
Duration=int.MaxValue, VaryByParam="none")]
Duration, VaryByContentEncoding, VaryByCustom,
VaryByHeader, VaryByParam
Location=“Server”|”Client”
CacheProfile=“X” – wez ustawienia z WebConfiga sekcji “X”
HttpResponse:
AddCacheItemDependency, AddFileDependency
Cache:
Cache.SetExpires, Cache.SetCacheability
Programowy dostęp do cache:
(string)Cache["CacheItem"];
Inne Filtry
RequireHttps – obligatoryjny https
ValidateInput,ValidationAntiForgeryToken – zwiazane z
zabezpieczeniami
AsyncTimeout, NoAsyncTimeout – dla anynchronicznych
kontrolerów
Życie aplikacji ASP.NET MVC
Receive a first
request
In the Global.asax file, Route objects are added
to the RouteTable object.
Perform routing
The UrlRoutingModule module uses the first
matching Route object in the RouteTable
collection to create the RouteData object, which
it then uses to create a RequestContext
(IHttpContext) object.
Create MVC request
handler
The MvcRouteHandler object creates an
instance of the MvcHandler class and passes it
the RequestContext instance.
Create controller
The MvcHandler object uses the
RequestContext instance to identify the
IControllerFactory object (typically an instance
of the DefaultControllerFactory class) to create
the controller instance with.
Życie aplikacji ASP.NET MVC cd.
Execute controller
The MvcHandler instance calls the controller's
Execute method.
Invoke action
Most controllers inherit from the Controller base
class. For controllers that do so, the
ControllerActionInvoker object that is
associated with the controller determines which
action method of the controller class to call, and
then calls that method.
Execute result
A typical action method might receive user input,
prepare the appropriate response data, and then
execute the result by returning a result type. The
built-in result types that can be executed include
the following: ViewResult (which renders a view
and is the most-often used result type),
RedirectToRouteResult, RedirectResult,
ContentResult, JsonResult, and EmptyResult.
Autoryzacja
Windows Authentication
Forms Authentication
->
FormsAuthentication.SetAuthCookie(),
Web.config: cookieless="UseUri“
ActiveDirectoryMembershipProvider).
SqlMembershipProvider
SqlMembershipProvider
web
site administration tool
http://msdn.microsoft.com/enus/library/ms228053%28v=vs.100%29.aspx
VSProject ASP.NET Configuration
IP - restrykcje
Web.config
<configuration>
<location path="Home“><system.webServer>
<security>
<ipSecurity enableReverseDns="true">
<clear/>
<add ipAddress="192.188.100.1"/>
<add ipAddress="169.254.0.0" subnetMask="255.255.0.0"/>
<add domainName="mydomain.com"/>
<remove domainName="otherdomain.com"/>
</ipSecurity>
</security>
</system.webServer></location>
</configuration>
Jak testować np redirect
[Test]
public void ShouldRedirectToTheNextConference()
{
var conferenceToFind = new Conference{Key = "thekey", Name = "name"};
var repository = new ConferenceRepositoryStub(conferenceToFind);
var controller = new RedirectController(repository);
RedirectToRouteResult result = controller.NextConference();
Assert.That( result.RouteValues["controller"],
Is.EqualTo("conference"));
Assert.That(result.RouteValues["action"],
Is.EqualTo("index"));
Assert.That( result.RouteValues["conferenceKey"],
Is.EqualTo("thekey"));
}
Jak testować np dostęp do cache
[Test]
public void CacheTest()
{
var fakeCache = MockRepository.GenerateStub<ICache>();
var controller = new HomeController(fakeCache);
fakeCache.Stub(x => x.Exists("test")).Return(false);
controller.CacheTest();
fakeCache.AssertWasCalled(x => x.Add("test", "value"));
fakeCache.AssertWasCalled(x => x.Get<string>("test"));
}
Jak testować np dostęp do sesji
[Test]
public void SessionTest() {
var controller = new HomeController();
var httpContext = MockRepository.GenerateStub<HttpContextBase>();
var mockSession = ockRepository.GenerateMock<HttpSessionStateBase>();
httpContext.Stub(x => x.Session) Return(mockSession).Repeat.Any();
const string key = "shopping_cart";
mockSession.Expect(x => x[key]).Return(null);
mockSession.Expect(x => x.Add(null, null)).IgnoreArguments();
mockSession.Expect(x => x[key]).Return(new Cart());
controller.ControllerContext =
new ControllerContext(httpContext, new RouteData(), controller);
controller.ViewCart();
mockSession.VerifyAllExpectations();
}
Konfiguracja
Web.config
Cache
Autentykacja
Połączenia (baza itd)
Kompilacja widoków
Kryptografia
Własna obsługa błędów, Własny routing
...
Konfiguracja - własne ustawienia
Proste ustawienia:
<appSettings>
<add key="MojeUstawienie" value="wartosc">
</appSettings>
ConfigurationManager.AppSettings["MojeUstawienie"]
Własne sekcje
Hierarchia konfigów
Aplikacja dziedziczy ustawienia z kilku poziomów
1.
2.
3.
4.
5.
Machine.config
c:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Config\mac
hine.config
Machine.web.config
c:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Config\mac
hine.web.config
Nadrzędne web.config
web.config
Ustawienia na niższym poziomie mogą nadpisywać
poprzednie wartości
Posadowienie aplikacji
Asp.NET Sevelopment Server (niedostępny spoza
maszyny)
IIS (domyślnie nieinstalowany)
Project -> publish
Pakiet (VS2010):
aspnet_regiis.exe –I (rejestracja asp – po doinstalowaniu)
Project -> Build Deplyment Package
Project.cmd
Ustawienia parametrów
Wymagany MsDeploy
Wersje konfiguracji:
.Net 4.0
http://blogs.msdn.com/b/webdevtools/archive/2009/05/04/webdeployment-web-config-transformation.aspx
Posadowienie aplikacji
Transformacje Web.config
http://msdn.microsoft.com/enus/library/dd465318%28v=vs.100%29.aspx
Śledzenie – web.config
1.
Wlączenie trace loga widocznego pod http://localhost/myapp/Trace.axd
<system.web>
<trace enabled="true" pageOutput="true" localOnly="true" />
</system.web>
Śledzenie – web.config
1.
…
2.
Dodanie logera
<system.diagnostics>
<trace><listeners>
<add name="WebPageTraceListener"
type="System.Web.WebPageTraceListener, System.Web,
Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"/>
</listeners></trace>
</system.diagnostics>
3.
Komunikaty: System.Diagnostics.Trace.Write()
Health monitoring
ASP.Net health monitoring -> http://msdn.microsoft.com/enus/library/bb398933%28v=vs.100%29.aspx
Lifecycle
Event
SQL
Provider
Error
Event
Audit
Event
Request
Event
Heartbeat
Event
Rules
EventLog
Provider
Custom
Provider
Custom
Event
ELMAH: Error Logging Modules and Handlers for ASP.NET->
http://www.hanselman.com/blog/ELMAHErrorLoggingModulesAndH
andlersForASPNETAndMVCToo.aspx
MVC - community
MVC Contrib:
http://mvccontrib.codeplex.com/
UI Helpers - Fluent html helpers
MVC Contrib:
http://mvccontrib.codeplex.com/
Fluent html helpers
@this.TextBox(x => x.FirstName).Class("required").Label("First Name:“)
@this.Select(x =>
x.ClientId).Options((SelectList)ViewData["clients"]).Label("Client:“)
@this.MultiSelect(x => x.UserId).Options(ViewModel.Users)
@this.CheckBox("enabled").LabelAfter("Enabled").Title("Click to
enable.").Styles(vertical_align => "middle")
UI Helpers - grid
<%= Html.Grid(Model).Columns(column => {
column.For(x => x.Id).Named("Person ID");
column.For(x => x.Name);
column.For(x => x.Gender);
column.For(x => x.DateOfBirth).Format("{0:d}");
column.For(x => Html.ActionLink("View Person", "Show",
new { id = x.Id})).DoNotEncode();
}) %>
MVC alternatywne silniki szablonów
MVC Contrib
Brail
NDjango
NHaml
Nvelocity
SharpTiles
Spark
StringTemplate
XSLT
Spark
Dystrybuowany w MVCcontrib
Wykorzystywany w Castle MonoRails
<ul>
<li each='var p in ViewData.Model.Products'>
${p.Name} !{Html.ActionLink[[ProductController]](c=>c.Edit(p.Id), "Edit")}
</li>
</ul>
Możliwość definiowania komponentów strony
Spark- przykład
<html>
<head>
<use content="head"/>
</head>
<body>
<Header/>
<use content="view"/>
<Sidebar/>
<Footer/>
<use content="tail"/>
</body>
</html>
<content name="head"> Views/Shared/_Sidebar.spark
<script src="~/content/js/jquery-ui-accordian.js"
once="jquery-accordian"></script>
</content>
<div id="sidebar">etc</div>
ASP.NET 2..3..4
MVC 3
Scaffolding (MvcScaffold integration)
Wsparcie dla projetów HTML 5
Domyślny silnik szablonów Razor
Cache-owanie na poziomie fragmentów strony
Wsparcie dla bezsesyjnych kontrolerów
Ulepszenia w zakresie walidacji, DI
MVC 4
Wsparcie dla aplikacji mobilnych szablony projektów itd
Rozszerzone wsparcie dla metod asynchronicznych
Asure SDK
ASP.NET 5
MVC 5
One Asp.Net
ASP.NET Identity
Bootstrap
Authentication filters
Filter overrides
Attribute routing
Literatura
Darmowe:
http://aspnetmvcbook.s3.amazonaws.com/aspnetmvcnerdinner_v1.pdf
http://github.com/jeffreypalermo/mvc2inaction
MVC: Inne podejścia
•
•
•
Fubu MVC
Mono Rail
Ruby on Rails in IronRuby
MVC: ASP.NET, FuBuMVC
•
•
•
•
•
ASP.NET MVC wystartował w końcu 2007
OXITE (referencyjna architektura) została wydana jesienią
2008. Po silnej fali krytyki zmieniono jej status “this isn't
supposed to be the reference application for ASP.NET MVC“
ASP.NET MVC RC2 - 4.03.2009
ASP.NET MVC 2 RC2 – przełom 2009/2010
FuBuMVC początkowo bazował na ASP.NET MVC (jako zbiór
helperów). Później dołączono do niego bardzo niewielki rdzeń
MVC.
• Duży zakres predefiniowanych behaviours
• Silnie nazywane metody w kontrolerach (wprowadzo je
częściowo w MVC)
• Convention over configuration
REST
Representational State Transfer – opracowany w 2000 r.
Nie jest z założenia związany z HTTP, ale w praktyce
wszystkie serwisy wykorzystuja HTTP
Zasób – samodzileny byt, obrazek, plik, transakcja/opis
towaru itd.
REST
Klient serwer
Bezstanowy
Cache friendly
Jednorodny interfejs
Identyfikacja zasobów
Manipulacja poprzez reprezentację
Samoopisujące wiadomości
Hipermedia
Warstwowa organizacja systemu
Kod na żadanie (opcjonalny)
WebApi
Lekki framework do budowy serwisów HTTP
Początkowo był rozszerzeniem WCF
Korzysta z routingu/infrastutury (np. validacje) MVC
Możliwe hostowanie w IIS lub we własnym procesie
Może pracować z przegladarkami/klientami
dektopowymi/u.mobilnymi
WebApi
Wspiera negocjację zawartości w zakresie
Formatu (Xml/Json/Custom)
Charset-u
Kodowania
Języka
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
WebApi
Wspiera Odata
Convention over Configuration – domyślne nazwy metod nie
wymagają rejestracji/atrybutów itd:
GET (Read)
PUT (Update)
POST (Create)
DELETE (Delete)
Można odejść od konwencji
[HttpGet]
public Auction FindAuction(int id)
{ … }
http://www.asp.net/web-api/overview/getting-started-withaspnet-web-api/tutorial-your-first-web-api
OData
Open Data Protocol
REST-owy protokół do realizacji operacji typu CRUD
Polecenia:
GET: pobiera kolekcję rekordów (jako dokument) lub pojedynczy rekord
(jako dokument).
POST: tworzy nowy rekord na podstawie danych z polecenia
PUT: Aktualizuje istniejący rekord
DELETE: Usuwa rekord
Install-Package Microsoft.AspNet.Odata
OData
Wspiera zapytania o dane na interfejsie WWW (atrybut
Queryable)
Sortowanie Api/Customer/?$orderby=Id
Sortowanie
/?$orderby=Id
Ograniczenie zwrotu /$top=2
Pomijanie /$skip=2
Filtrowanie /?$filter=Orders/any(order: order/Quantity ge 10)
Łączenie operacji /?$orderby=Id&$skip=1&$top=2