webForumDet fria alternativet

Hjälp med Razor

.NET

10 svar · 3 321 visningar · startad av Mika3l

Medlem sedan nov. 20018 492 inlägg
Frågan#1

Hej!
Nu är jag tillbaka med nybörjarfrågor men denna gång med Razor. Läste om det och tyckte att det kändes enklare så nu håller jag på att konvertera min sida (som jag har tagit upp tidigare) till Razor istället. Det går rätt så bra men det är lite svårt att hitta info när jag kör fast, har tre frågor där jag inte kommer så långt.

1. Formatera datum, hur? Ska skriva ut data från databas och använde förut <%#DataBinder.Eval(Container.DataItem,"f_date","{0:MMM yyyy}")%>.
EDIT: Löste sig naturligtvis med en gång: @String.Format("{0:MMM yyyy}", d.f_date)

2. När jag ska skriva ut en lista från min databas vill jag att tre poster loopas horisontellt innan en radbrytning. Tyckte det var väldigt enkelt och smidigt förut med RepeatColumns i DataList men nu verkar enda lösningen vara listor i CSS eller någon form av manuell beräkning för att sätta in </tr><tr>?
Går det att lösa på ett enklare sätt med tabeller? Vill använda tabeller för jag tycker att jag får bättre kontroll och att det är enklare.

<ul class="issueslist">
@foreach(var d in connection.Query(SQL)) {
    <li class="issueslist">
        <h3>#@d.f_nr&nbsp;@d.f_date</h3>
        <a id="readissue" href="read.cshtml?id=@d.f_iid" title=" Click to read the issue ">
            <img src="images/covers/@d.f_pic
.jpg" class="issue_img" />
        </a>
        <a id="readissue" href="read.cshtml?id=@d.f_iid">Read</a> |
        <a href="issuesinfo.cshtml?id=@d.f_iid">More info</a>
    </li>
}
</ul>

3. Går det att skapa en databaskoppling som alla sidor använder? Tycker det känns onödigt att behöva göra en ny koppling flera gånger. Tänkte om det går att lägga in i _PageStart eller något liknande så att kopplingen bara behöver göras en gång? Har ju några variabler där men varje måste ju deklareras i varje dokument som ska använda den.

@{
    Layout = "_template.cshtml";
    PageData["fbooklink"] = "<a href=\"http://www.facebook.com/pages/Sunday-Morning-Magazine/163709807002555\" target=\"_blank\">Facebook</a>";
    PageData["mailto"] = "<a href=\"mailto:%69%6e%66%6f%40%73%75%6e%64%61%79%6d%6f%72%6e%69%6e%67%6d%61%67%61%7a%69%6e%65%2e%73%65\">&#105;&#110;&#102;&#111;&#64;&#115;&#117;&#110;&#100;&#97;&#121;&#109;&#111;&#114;&#110;&#105;&#110;&#103;&#109;&#97;&#103;&#97;&#122;&#105;&#110;&#101;&#46;&#115;&#101;</a>";
 }
@{
    var mailto = PageData["mailto"];
}
Medlem sedan juni 20003 076 inlägg
#2

2.
Det är rätt enkelt att göra en vanlig for-loop till det.
Jag har inte i huvudet hur man skriver mod-taggen men typ så här:

@{
     for (var i = 0; i < Model.Users.Length; i++)
     {
          <span>@Model.Users[i].FirstName</span>
          if(i % 3 == 0)
          {
                 <br />
           }
     }
}

Som du ser använder jag Model i loopningen vilket leder till din fråga nr 3:
Databaskopplingar hör inte hemma i vyer utan i controllern som vyn använder. Controllern fyller sedan en modell som vyn implementerar.
Om du har en sida (vy) som listar användare ur en databas så skapar du lämpligtvis en model som heter något i stil med UserDisplayViewModel.
Och överst i vyn:

@model UserDisplayViewModel
...

Och modellen kan innehålla allt möjligt:

public class UserDisplayViewModel
{
     public IList<User> Users { get; set; }
     ...
}

Och fyller propertyn Users gör du således i din actionmetod i controllern.

För att använda något på alla sidor som t.ex. en meny så gör du först en vanlig vy som innehåller menyn. Denna vy kan du sedan länka in via RenderAction i din mastersida.

Medlem sedan nov. 20018 492 inlägg
#3

Tackar för hjälpen!
Hänger inte med till 100% men jag är ju väldigt ny i området och sättet att programmera på (van gamla ASP), ska googla lite så kommer jag nog vidare lätt. Tar gärna emot länkar! :)

Medlem sedan maj 20012 812 inlägg
#4

Mika3l skrev:

Tackar för hjälpen!
Hänger inte med till 100% men jag är ju väldigt ny i området och sättet att programmera på (van gamla ASP), ska googla lite så kommer jag nog vidare lätt. Tar gärna emot länkar! :)

När du programmerar i MVC så skall du inte har någon som helst kod i dina views (alltså dina aspx-filer där du använder Razor). Den enda logik som får finns där är logik som är kopplade direkt till hur du vill visa din data, typ formatering av datumtid! Eller dina extra radrytningar efter 3 rader osv osv..

All annan logik skall finnas i din controller. Och du skickar sedan det du vill visa tillbaka till din view.

Så allt det du kunde i ASP är nu bara en belastning för dig, då du under inga omständigheter skall använda det sättet om du går efter en MVC lösning. MVC använder man när man vill underlätta UnitTesting och då lägger man all logik i sin Controller och så kör man en unittest på den controllern och kontrollerar att de skickar ut rätt saker. Om du då har logik i din View så kommer dina unittest aldrig att fungerar mot din controller eftersom det du får tillbaka från din controller inte är det som du förväntar dig utan något som måste behandlas ytterligare!!!

- M

Medlem sedan nov. 20018 492 inlägg
#5

Ok, ska kolla mer på controllers och försöka till det rätt! :)

Har ytterligare en fråga!
Jag har ett gäng namn som jag hämtar från min databas, om jag klickar på ett av dom vill jag visa lite ytterligare info till höger om listan. Går det att lösa på något smidigt sätt m.h.a Razor eller behöver jag blanda in egen Ajax, eller kanske båda delar?

@{
    var connection = PageData["connection"];
    var continfo = "";
    
    var SQL = "SELECT f_cid, f_name FROM tblCont ORDER BY f_name";
}
  

<h1>Contributors</h1>
<div id="cont_left">
<ul>
    @foreach (var d in connection.Query(SQL)) {
        <li><a href="?cid=@d.f_cid">@d.f_name</a></li>
    }
</ul>
</div>

<div id="cont_right">
@continfo    
</div>
Medlem sedan juni 20003 076 inlägg
#6

Precis som Gladh skriver så "FÅR" du inte skriva på det sättet du gör ovan.
En selectsats är förbjuden i en vy. Den hör hemma i controllern alt. bakomliggande datalager.
Typ så här ska du göra:
Controller:

public class ContentController : Controller
{
     public ActionResult Index(int id = 0)
     {
          var model = new ContentModel();

          var SQL = "SELECT f_cid, f_name FROM tblCont ORDER BY f_name";
          model.ContentItems = dinDBKoppling(SQL).ToList();

          if(id >0)
          {
               model.DetailContent = dinDBKoppling("select * from tblCont where ID = " + id).FirstOrDefault();
          }

          return View(model);
     }
}

Model:

public class ContentModel
{
     public IList<Content> ContentItems { get; set; }
     public Content DetailContent {get; set; }
}

View:

@model ContentModel

<h1>Contributors</h1>
<div id="cont_left">
<ul>
    @foreach (var content in Model.ContentItems) {
        <li><a href="?id=@content.f_cid">@content.f_name</a></li>
    }
</ul>
</div>

<div id="cont_right">
@{ 
     if(Model.DetailContent != null) {
       <h1>@Model.DetailContent.f_name</h1>
     }
}
</div>

För att se detaljinformationen surfar du helt enkelt till /Content/Index?id=123 eller gör en routing så att du kan skriva /Content/Index/123.

Sen är det snudd på förbjudet att skriva statiska selectsatser som jag visar ovan utan de hör hemma i ett datalager eller ännu hellre i en ORMapper som ex. NHibernate.

Sen kan du blanda in Ajax om du vill men jag tycker nog du ska lyckas få till det på detta sätt först.

Hoppas det blev lite tydligare! :)

Medlem sedan nov. 20018 492 inlägg
#7

Stort tack! Ska försöka mig på det här nu så att det blir helt rätt! :)
Vad menar du med statiska selectsatser, är det hämtningen av data i vyn du menar?

Vad bör dokumenten döpas till för att hittas automatiskt? _Controller.cshtml och _Model.cshtml? Nån speciell mapp de behöver ligga i?

Ville gärna använda Ajax för att slippa att ladda om sidan och har fattat som att ASP.NET har bra support för det, men det är väl inte hela världen. Börjar så här iaf. :)

Vad är fördelen med att använda routing istället för querystring?

Återigen, stort tack för hjälpen! :)

Medlem sedan juni 20003 076 inlägg
#8

Vad menar du med statiska selectsatser, är det hämtningen av data i vyn du menar?

Det är denna rad i controllern jag menar:

var SQL = "SELECT f_cid, f_name FROM tblCont ORDER BY f_name";

Om du har 1000 liknande rader och sedan bestämmer dig för att döpa om något i databasen så har du en del jobb att gå igenom och ändra alla strängar.
Jag rekomenderar istället att använda en ORMapper så är problemet löst!
Googla på "OR Mapper" och kolla om det kan vara nått för dig.

Vad bör dokumenten döpas till för att hittas automatiskt? _Controller.cshtml och _Model.cshtml? Nån speciell mapp de behöver ligga i?

Vyerna (.cshtml) kan heta vad du vill, modeller och controllers är vanliga .cs filer.
Enklast är om du skapar ett nytt MVC projekt i Visual Studio, då ser du hur mappstrukturen ser ut. Sen går det att ändra strukturen om man vill i efterhand men det är en bra start. Precis som namnet säger (M V C) så skapas det en mapp för varje bokstav.

Vad är fördelen med att använda routing istället för querystring?

De båda lever i symbios med varandra, routing används för att få snygga sökvägar och även sökmotorsoptimerade länkar. Routing används också för att peka på vilken actionmetod i vilken controller man är ute efter.
Standardrouting anges så här: /[Controller]/[Action]/[Extra parametrar], ex. /Users/Detail/123

Medlem sedan nov. 20018 492 inlägg
#9

Nu är jag tillbaks i utvecklartagen igen efter ett litet uppehåll!
Först, tack för all hjälp! :)
Har testat din kod nu doggelito, men får det inte att fungera. Verkar som att controllern inte laddas in?
Får "CS0103: Namnet model finns inte i den aktuella kontexten" på raden "@model ContentModel". Controllern är döpt till _controller.cs och modellen till _model.cs, båda ligger i mappen bin. Behövs _ för .cs-filer förresten?

Medlem sedan nov. 20018 492 inlägg
#10

Upptäckte att det skulle va stort m, @Model. ;)

Fick dock fel när det väl drog igång: "Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Det går inte att utföra bindning under körning för en null-referens"

@foreach (var content in Model.ContentItems) {

controllern:

using System;
using System.Collections.Generic;
using System.Web;

var connection = Database.Open(smm);

/// <summary>
/// hämtar deltagare till contributors.cshtml
/// </summary>
public class ContentController : Controller
{
     public ActionResult Index(int id = 0)
     {
          var model = new ContentModel();

          var SQL = "SELECT f_cid, f_name FROM tblCont ORDER BY f_name";
          model.ContentItems = connection(SQL).ToList();

          if(id >0)
          {
               model.DetailContent = connection("select * from tblCont where ID = " + id).FirstOrDefault();
          }

          return View(model);
     }
}
Medlem sedan juni 20003 076 inlägg
#11

Controllern är döpt till _controller.cs och modellen till _model.cs, båda ligger i mappen bin. Behövs _ för .cs-filer förresten?

Filerna ska inte heta _...cs. Heter klassen ContentController så döp filen till ContentController.cs. Alla controllers lägger du i mappen Controllers.
Alla modeller lägger du i mappen Models och alla vyer lägger du i Views i respektive undermapp. Ex. vyerna för ContentController lägger du i Views/Content/.
Som jag skrev tidigare, skapa ett tomt MVC projekt i Visual Studio så ser du hur det är uppbyggt.

var connection = Database.Open(smm);

Denna ska absolut inte ligga löst utanför en klass! In med koden i din index metod. Funkar inte det så får du se över din databashanteringskod! ;)

265 ms totalt · 4 externa anrop · v20260731065814-full.a51de22e
122 ms — deklarationer (db)
0 ms — hämta statistik (cache)
137 ms — hämta tråd, inlägg och bilagor (db)
124 ms — ändringar (db)