.NET Core MVC _Layout paraméter átadás - adatbázis elérése
2019-07-09T15:59:21+02:00
2019-08-07T10:34:23+02:00
2022-08-11T14:15:31+02:00
zidan26
Sziasztok,

kezdő vagyok ebbe a témában. Egy dotnet core programot készítek C# -nyelvi környezetben.
Szóval van egy "_Layout.cshtml" fájlom. Ugye ez arra szolgál hogy ebbe töltődnek be az egyes részek. Elvileg ez töltődik be először. Utána a hozzá tartozó pl. "Index.cshtml". Szóval én ebben az "index"-ben én adatbázis kapcsolatot létesítek és ha változtatok akkor az kihat "_Layout.cshtml"-re is. Ugyanis a változtatást a "_Layout.cshtml"-ben lévő "navbar"-ban szeretném megmutatni. Csak sajna nem megy. Kérhetnék ebben egy kis segítséget? Már egész nap "google"-zek de nem találtam megoldást. Vagy lehet találtam csak elsiklottam mellette.
Még itt szeretném megragadni az alkalmat hogy ebben a "_Layout.cshtml"-ben még az első megnyitásnál jó lenne látni az adatbázis tartalmát. Konkrétan egy évszámot és hónapot szeretném lekérni. Ugyanis ez egy könyvelői program lenne.

Megjegyzem ha valaki megsértődne azon hogy a témakörökben nem jeleztem az adatbázis elérést sajna csak három témakört lehetett megjelölni, ezért elnézést kérek.

Köszi előre a segítséget.

tibi
Mutasd a teljes hozzászólást!
Legegyszerűbben úgy férsz hozzá az adatbázishoz ha a _Layout.cshtml tetejére beszúrod ezt, értelemszerűen a namespace lecserélésével:

@using Microsoft.EntityFrameworkCore @using WebApplication1.Data @inject ApplicationDbContext DbContext @{ var users = await DbContext.Users.ToListAsync(); }
Ezek után a változó innentől elérhető bárhol, pl ha a title-t lecseréled erre:

<title>@ViewData["Title"] - @users.Count</title>
Mutasd a teljes hozzászólást!

  • Továbbá

    "Elvileg ez töltődik be először. Utána a hozzá tartozó pl. "Index.cshtml"."

    Ez pont fordítva van, így a x.cshtml-ben használhatod a következőt:

    @{ ViewData["MódosítottAdat"] = módosítottAdat; }

    A _layout.cshtml-ben pedig, mert ez fut le utoljára, nem elsőként:

    @{ var módosítottAdat = (cast???)ViewData["MódosítottAdat"]; }
    Mutasd a teljes hozzászólást!
  • szia,


    köszi a válaszod...megkérdezném hogy ez a fajta megoldás :

    @await Component.InvokeAsync("DB_")

    ugye csináltam egy ilyen:

    public class DB_ViewComponent : ViewComponent

    amihez csinálam egy view-t és abban visszaadom a megfelelő értéket....

    nagyon gáz?

    ...tibi
    Mutasd a teljes hozzászólást!
  • Ez egy elegáns megoldás, de mérlegelni kell hogy az újrahasznosítható komponensek közül, vajon a többi projektben is használható lesz-e. 

    Érdemes megnézni a projektben a _LoginPartial.cshtml, ugyan csak egy feltételes elágazás van benne, de jól szemlélteti hogy egyszerűbben is lehet kis beszúrható kütyüket készíteni.
    Mutasd a teljes hozzászólást!
  • "_LoginPartial.cshtml"?...hmm nem találtam, de beleszaladtam egy másik problémába...lehet új kérdést érdemelne...szeretném bejentkezéskor leelenőrizni az adatbázisban eltárolt jelszavat...a model validációt használom...az appsettings.json-ban tárolom a connectionstring-et, de sehogyan sem tudom bevinni a model validációjába....

        public class ValidationFromMaterDB{

            SQLCommandCS instanceSQLCommandCS;
            

            public ValidationFromMaterDB() {
                
                instanceSQLCommandCS = new SQLCommandCS();

            }
            public bool userValidation(string usrName) {

                string sql = "";
                int cntUsr = 0;
                string connectionString = Configuration["ConnectionStrings:MasterConnection"];
                using (SqlConnection connection = new SqlConnection(connectionString))
                {
                    connection.Open();
                    sql = instanceSQLCommandCS.getUserNameIsExsistInTbUsers(usrName);
                    SqlCommand commandUserNameIsExsistInTbUsers = new SqlCommand(sql, connection);
                    using (SqlDataReader dataReader = commandUserNameIsExsistInTbUsers.ExecuteReader())
                    {
                        while (dataReader.Read())
                        {
                            cntUsr= Convert.ToInt32(dataReader["Value"]);                        
                        }
                    }
                    connection.Close();
                }
                return (cntUsr > 0);
            }
            public string getPasswByUser(string usrName)
            {

                string sql = "";
                string varUsrPassw = "";
                string connectionString = Configuration["ConnectionStrings:MasterConnection"];
                using (SqlConnection connection = new SqlConnection(connectionString))
                {
                    connection.Open();
                    sql = instanceSQLCommandCS.getUserPasswFromTbUsersByUserName(usrName);
                    SqlCommand commandUserNameIsExsistInTbUsers = new SqlCommand(sql, connection);
                    using (SqlDataReader dataReader = commandUserNameIsExsistInTbUsers.ExecuteReader())
                    {
                        while (dataReader.Read())
                        {
                            varUsrPassw = (dataReader["UsrPassw"].ToString());
                        }
                    }
                    connection.Close();
                }
                return varUsrPassw;
            }

        }

        public class LogInPasswValidationAttribute : ValidationAttribute
        {
            private ValidationFromMaterDB parValidationFromMaterDB;
            

            public LogInPasswValidationAttribute()
            {
            parValidationFromMaterDB = new ValidationFromMaterDB();
            }

            protected override ValidationResult IsValid(object value, ValidationContext validationContext)
            {
                LogInM varLogInM = (LogInM)validationContext.ObjectInstance;
                if (!(parValidationFromMaterDB.getPasswByUser(varLogInM.UsrName) == value.ToString()))
                {
                    return new ValidationResult(ErrorMessage = " hiabjelzes!");
                }
                return ValidationResult.Success;
            }
        }

    ...szóval ezzel van a probléma: ' Configuration["ConnectionStrings:MasterConnection"];'

    Mert ugye a LogInM modelből fog hívódni:

    [Display(Name = "Jelszó")]
    [LogInPasswValidationAttribute()]
    public string UsrPassw { get; set; }

    ....sajnos én a configuration-t nem tudom oda bevnni probáltam a konstruktorába (LogInM  parLogInM =new LogInM (Configuration) a controllerből természetsen) átadni de mindig a post után non-instance hibát kaptam...na jó nem pontosan ezt a hibát csak valami hasonlót írt ki....de még a [HttpGet]-nél jó volt csak a [HttpPost] mikor már kiértékelni kellett volna, sőt el sem jutott az action controller metódusáig ami lekezelné már előtte írta a hibát....

    szóval...jó lenne erre valami megoldás....
    Mutasd a teljes hozzászólást!
  • Kedves kolléga!

    Egyfelől ez egy új kérdés, másfelől erősen javasolt, hogy kezdetnek csinálj végig legalább egy tutorialt!

    A kódod alapján nem elég, hogy teljesen rosszul akarod felépíteni az alkalmazásodat (nem követve az ajánlott mintákat), de ráadásul ránézésre komoly biztonsági problémák merülnek fel: láthatólag a jelszót szövegesen tárolod, a lekérdezés pedig - nagy valószínűséggel - SQL injection-re ad lehetőséget.

    ASP.NET Core esetén célszerű Entity Framework-öt (többek között SQL injection kivédésére), helyi felhasználó kezelésre pedig Identity-t használni (ez sózott jelszó hash-t használ gyárilag).

    A legjobb lenne, ha kezdetnek megnéznéd a Visual Studio által, új project létrehozásakor generált példa alkalmazást!
    Mutasd a teljes hozzászólást!
  • Amint hazaértem ezt szerettem volna írni, bár kicsit kedvesebben, kiegészítve hogy ne MVC hanem inkább Razor és az ajánlott authentikációval.
    Mutasd a teljes hozzászólást!
  • Ezúton elnézést akkor, ha túl nyersre sikerült, bár én úgy gondolom, kizárólag tényszerű voltam.
    Mutasd a teljes hozzászólást!
  • szia,

    én ezt a tutorialt végigcsináltam. Átnéztem. Akkor ezek szerint nem jól ha azt mondod nézzem át. Még egyszer neki fogok állni átnézni ha így gondolod.
    SQL injection...elnézést de nem tettem oda a teljes kódot. Igen igazad van. Engem most inkább az érdekelt volna hogy tudnám így megcsinálni, már mint hogy is tudnám elérni az application.json-t Modelből vagy eppen a validációból.
    Nem jól értelmezed, igen is figyelek a hashre. Éppen hogy az adatbázisban tárolt hasht akarom összehasonlítani a megkapott hashel.
    Mert ugye úgy kell majd amit még nem csináltam meg hogy az sql injectionra figyelve hash-elem a begépelt jelszavat és a tárolt hash kódot kiveszem a user alapján. Na de mit ér az egész ha nem tudom lekérdezni a hash-elt jelszavat.
    Nem szeretnék razort használni.
    Nem vagyok sértődékeny típus. Sőt a kritikát is jól viselem. Nem vagyok mindentudó ezért kérem a segítségeteket akik már ebben jártasak.

    tibi
    Mutasd a teljes hozzászólást!
  • Még a végére beszúrhattál volna egy mondatot:

    De jobb lenne ha megismerné a MVC-t és csak "ViewModel"-ekkel kötné össze az adatbázist a html-view-ekkel.
    Mutasd a teljes hozzászólást!
  • Ha átnézted, akkor miért saját autentikációt fejlesztesz, ahelyett, hogy ezt egy gyári MiddleWare-re bíznád, és egyszerűen az [Authorize] attribútumot használnád az azonosításhoz?

    Az application.json feldolgozását nem a controller-ből kéne végezned, hanem a MiddleWare konfigurálásakor. Ott kiszeded a connection string-et, felhasználod az adatbázis elérést biztosító objektumodban, és azt kéne beinjektálnod oda, ahol az szükséges (DI), nem a connection string-et. Nem muszáj EF-et használni, de valami ilyesmi mintát kéne akkor is követned.

    Amennyiben valamilyen application.json-ban tárolt paramétert szeretnél felhasználni egy controller-ben (a connection string nem ilyen!), akkor az IOptions a barátod.

    Nem szükséges Razor Pages-t használni, bár úgy tűnik, a Microsoft ezt az irányt erősítené mostanában. A Razor maga a view-kban alkalmazott, feldolgozó nyelv.
    Mutasd a teljes hozzászólást!
  • ...azon vagyok hogy megismerjem...gondolom könnyebb beszólogatni mint elmagyarázni bizonyos dolgokat :)...
    Mutasd a teljes hozzászólást!
  • Párszáz/párezer oldalas doksikat elmagyarázni kicsit nehéz :)

    Igazán a kulcsszavak és szemlélet átadását várhatod el, mint pl. hogy keress az MVC-re, ne direkt akard olvasni az adatbázist a view-ekben, hanem a kontrollerben szedj össze adatokat és add át a POCO-ban, stb.
    Mutasd a teljes hozzászólást!
  • Azért nem a beépített autentikációt használom mert:
    1. Őszintén megmondva nem vagyok annyira profi hogy átlássam,
    2. mivel nem látom át neheze tudok benne módosítani
    3. delphiben megírt alkalmazást kell átvinnem erre a felületre-//ez olyan kijelentés volt nem indok//

    Leírom az egészet és bízom abban hogy nem figurázza ki valaki bár ennek kicsi az esélye. :)
    Szóval ez egy könyvelői program lenne aminek az elején lesz az autentikáció. Itt egy master adatbázishoz csatlakozna ami mssql adatbázisban van. Siker esetén a felhasználó alapján beolvassa a hozzá tartozó adatokat. (csatlakozik az utoljára csatlakozott adatbázishoz ez felhasználó alapján, minden cég rendelkezik egyedi azonosítóval, ez alapján vannak elkülönítve az egyes adatbázisok,ezen adatbázisokon belül be kell olvasni az utoljára könyvelt évet és hónapot )

    Persze ha kijelentkezik akkor mindent felszabadítani és újracsatlakozás esetén újra beolvasni az adatokat.

    Az elképzelésem az volt eddig hogy az application.json-ban eltárolom a master utat. A többi már a usertől függ.

    Igen tudom hogy még sokat kell tanulnom a dotnet cort de éppen azon vagyok mert meg akarom tanulni.
    Mutasd a teljes hozzászólást!
  • Mi az az MVC lényege? Én úgy olvastam hogy Model View,Controller.
    Model-ben megkreáljuk magát a struktúrát és a validálást is itt tesszük, amit a View megjelenít,a controllerben végzünk el minden mást. 

    lehet én látok valamit rosszul leírom:

    Van egy SettingsController-em. A controller meg kapja a konstruktron át

    public SettingsController(IConfiguration configuration) {

    a konfigurációs példányt. Innen le is tudom kérni a model-hez tartozó adatokat, mint pl ha el mentettem a felhasználó nevét akkor be is tudom tölteni. Maga a modell nem tudja elérni a validáció során a szükséges adatokat, tehát az adatbázist. Nem a controller.
    Én pont azt szeretném amire ki van találva az MVC. Mindent a maga helyén elvégezni.
    Mutasd a teljes hozzászólást!
  • Engem most inkább az érdekelt volna hogy tudnám így megcsinálni, már mint hogy is tudnám elérni az application.json-t Modelből vagy eppen a validációból.

    Konfiguráció példa:

    public class Company { public string Name { get; set; } public string Url { get; set; } }
    A Company class-t a Startup.cs, ConfigureServices metódusban beállítod így:

    services.Configure<Company>(Configuration.GetSection(nameof(Company)));
    Az appsettings.json fájl pedig ez kerül:

    "Company" : { "Name": "Cég neve", "Url": "http://blablaurl" }
    Használni pedig a ValamiController.cs-ben úgy tudod, hogy a konstruktor paraméterébe beállítod valahogy így:

    readonly Company _company; public Valami(IOptions<Company> company) { _company = company.Value; }
    Mutasd a teljes hozzászólást!
  • "Éppen hogy az adatbázisban tárolt hasht akarom összehasonlítani a megkapott hashel."

    Ez hibás elgondolás. nem hash-t hasonlítunk hash-el. A kapott jelszó és a hash validálásából kapott true vagy false mondja meg hogy a jelszó jó-e.

    Én bcrypt-et használok (BcryptNet/bcrypt.net)
    Mutasd a teljes hozzászólást!
  • A ConnectionString-hez is a Startup.cs-ben kell beállítanod a a következőt, fenti példát követve:

    services.AddTransient<IConfiguration>(i => Configuration);
    Controllerben meg:
    readonly Configuration _configuration; public Valami(IOptions<Company> company, IConfiguration configuration) { _company = company.Value; _configuration = configuration; }
    Mutasd a teljes hozzászólást!
  • Az nem lehet indok, hogy nem használsz egy standard eszközt és eljárást, mert nem látod át. Meg kell tanulni, nem atomfizika, hülyebiztos API-t kell csak hívogatni. Ha nem így teszel, a felhasználóidat sodrod veszélybe: az autentikáció kritikus pont minden alkalmazásnál. Ha a linkelt tutorialt végigcsinálod, vagy megnézed, hogy működik a VS template alkalmazás, már nagyjából képbe is kerülsz.

    Valóban, az eseted nem triviális. Én valahogy így csinálnám:

    A Master adatbázisod nyugodtan használhat Identity-t. Elég rugalmas egyedi igények kezelésére is, pl. többféle bejelentkezés. A felhasználóknak egy saját property-t definiálsz, ami azonosítja az egyedi adatbázisát. Annak jelszavát vagy a felhasználó adja meg bejelentkezéskor (ezt akkor ne tárold, mert csak visszafejthetően tudnád megtenni), vagy a szerver tárolja, mert közös, de a lényeg, hogy össze tudod rakni az egyedi connection string-et.

    Egy Authorization Filtert használnék, ami minden kéréskor lefut és ha a felhasználó azonosított, akkor a fentiek alapján összerakja a connection string-et és átadja a hívás helyének (HttpContext.Items segítségével). A controllered így létre tudja hozni az adatelérési objektumot.

    public class DbAccessAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext context) { if (context.HttpContext.User.Identity.IsAuthenticated) { string connString = "...conn string létrehozása..."; context.HttpContext.Items["ConnString"] = connString; }

    Használata pl. egy abstract base Controller osztályban:

    [DbAccess] public abstract class MyControllerBase : Controller {

    Innen származtathatsz minden controller-t, így minden kéréskor ott lesz a connection string a HttpContext.Items-ben, ha a felhasználó azonosított.

    Elérése egy controller metódusban:

    [HttpGet] public IActionResult MyMethod() { var connString = HttpContext.Items["ConnString"];

    Ezt utána tovább lehetne gondolni, hogy DI-t használjon, de azt már rád bízom.
    Mutasd a teljes hozzászólást!
  • nagyon érdekes...szóval akkor azt hogy oldanád meg nagy vonalakban:
    -van egy áruszámlám, annak van egy egyedi azonosítója és a modell validációnál akarnám ezt megoldani? lehetséges egyáltalán ez?
    -ugye ez úgy nézne ki hogy lenne egy modal-context, amiben van egy <form> egy modell beolvasva és szeretném a modell validációval megoldani hogy itt a formon adja ki nekem a hibajelentést. "ValidationAttribute"-tal megoldható lenne? esetleg valami mással?

    mert ide is adatbázis elérés kell, mert ezek az adatokat az adatbázisban tároljuk, tehát :

    lenne egy modellem:

            [ValidationSzamlaEgyediAzonosito()]       
            public string SzamlaEgyediAzonosito { get; set; }

        public class ValidationSzamlaEgyediAzonositoValidationAttribute : ValidationAttribute
        {
            public ValidationSzamlaEgyediAzonositoValidationAttribute()
            {
               
            }

            protected override ValidationResult IsValid(object value, ValidationContext validationContext)
            {
               
    valamilyen programkod ....
               
            }
        }


    de ujfent nem tudom elérni innen az adatbázist....hmmm...remélem értitek mire akarok kilukadni...ha nem ...most próbálok egy olyan általános megoldást ami minden dologra jó lenne mint a usernél mint a későbbiekben...mert itt már az authorizationfilter nem fog működni...
    Mutasd a teljes hozzászólást!
  • van egy áruszámlám, annak van egy egyedi azonosítója és a modell validációnál akarnám ezt megoldani

    Mármint megoldani mit? Adatbázisból validálni?

    Erre inkább használd a gyári [Remote] ValidationAttribute-ot. Doksi itt, másik példa itt.

    A legtöbb felmerülő problémára van beépített, már jól megírt megoldás, amit csak használni kell.
    Mutasd a teljes hozzászólást!
  • ...amúgy még a válaszok alapján keresgélek olvasok és a lehető legjobbat akarom kiválasztani de csak nyugodtan írjatok tanácsot szívesen fogadom és biztos hogy utána nézek...
    Mutasd a teljes hozzászólást!
  • Azt látom hogy magát az ASP.NET Core-t nem ismered. Nem Service-ekben gondolkodsz.

    Dependency injection in ASP.NET Core

    Ha SqlClient-et használsz is ugyan úgy kell eljárni, mint ha EntityFramework lenne a rendszered alatt és pontosan hogy IAuthorizationFilter-t kell használni.

    public class ValidationSzamlaEgyediAzonositoValidationAttribute : AuthorizeAttribute, IAuthorizationFilter { public void OnAuthorization(AuthorizationFilterContext context) { // Itt hozzáférsz a service-ekhez. _configuration = context.HttpContext.RequestServices.GetService<IConfiguration>(); // Itt példányosítod az SqlConnection-t. } }
    Mutasd a teljes hozzászólást!
  • Köszön szépen mindeni válaszát. Czirok Ferencet jelölöm meg a"elsfogadás megoldásként" az eredeti kérdésem megoldására. Hangsúlyozom a másik kérdésben is köszönöm a válaszokat sokat segítettetek.
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd