ASP.Net MVC 4 i User Id

Radim na jednoj aplikaciji i trebao mi je UserId trenutnog korisnika, s obzirom da radim u novom asp.net mvc4 frameworku i njegovim defaultnim authorization i authentication modelom cijelo popodne se zajebavam s tim. I sad na kraju dana otkrijem u biti kako je to jednostavno. Ukoliko nekom bude trebalo za buduće evo riješenja:

Tamo gdje trebate pozvati userid jednostavno otipkajte ovo:

@WebSecurity.CurrentUserId

Znači npr imate neku formu i trebate u bazu spremiti userid jednostavno uradite ovo:

             @using (Html.BeginForm())
                {
                    <fieldset>
                        <div class="field-group">
                            <div class="field">
                                @Html.EditorFor(model => model.Title)
                                @Html.ValidationMessageFor(model => model.Title)
                                @Html.LabelFor(model => model.Title)
                              
                            </div>
                            <div class="field">
                                @Html.TextBoxFor(model => model.UserId, new { @Value = WebSecurity.CurrentUserId })<span>*</span>
                                @Html.ValidationMessageFor(model => model.UserId)
                                @Html.LabelFor(model => model.UserId)
                              
                            </div>
                        </div>
                      
                        <input type="submit" value="Spremi" class="btn btn-small btn-success" />
                      
                    </fieldset>
                }

Eto nadam se da će nekom biti od pomoći.

Pozdrav.

MOzda nije mjesto ovdje ali da pitam…mozes li ukratko reci nesto u asp-u msm gdje se primjenjuje itd. jer prvi put cujem za to :slight_smile:

well, asp kao takav nema nikakve veze sa današnjim asp.netom. ASP = Active Server Pages to je Microsoftov “odgovor” na PHP i sl. skriptne jezike koji su se ili se koriste za izradu raznih web elemenata od APIja, Frameworka, Backend sustava itd.

ASP.net je više od skriptno jezika jer je u njega ugrađen kompletan .net framework koji onda možeš koristiti za razvoj. ASP.net se obično upotrebljava u enterprise riješenjima gdje igraček poput PHPa nisu dorasle izazovima ili bi se trebalo puno više namučiti nego što to biva kad radiš s moćnom alatkom poput ASP.net.

ASP.net MVC je Model-View-User framework razvijen od strane Microsofta kako bi ovu tehnologiju približio širokim masama i malo popularizirao dosta zapostavljenu tehnologiju za izradu web stranica.

E sad problem kod .net je taj da stvarno moraš znati programirati i to u OO(objektno orijentiranoj) paradigmi. Dakle .Net for Dummies tu ne prolazi, jer je potrebno stvarno svega znati da bi se snašao i iskoristio dio potencijala kojeg ovaj framework pruža.

Ovo je ovako ukratko i ovo je moje mišljenje. Dopuštam da se drugi ne slažu sa mnom i volio bih da ne ulazimo u rasprave tipa “čiji je veći” jer stvarno za to nema potrebe, a ako baš želite onda otvorite jednu flame temu u birtiji pa ćemo tamo flameati, :zub:

MVC4 ima ugrađen SimpleMembershipProvider iz WebPages frameworka (WebMatrix IDE), koji koristi u pozadini DotNetOpenAuth za OpenID i oAuth prijave (google, twitter, fejs, …).

Jedina ‘caka’ koju sam ja imao sa tim SimpleMembProviderom je spojiti ga sa mojim klasama i DataContextom (EntityFramework 4.1/4.3/5 sa Code First pristupom) - znaci izbacio sam DataContext koji dodje u “paketu”, i hookao svoj putem InitializeSimpleMembershipAttribute klase (atribut za kontroler, dodje u predlosku novog MVC4 projekta).

Uglavom, dovoljno je izmjeniti liniju unutar SimpleMembershipInitializer konstruktura u ovo:

WebSecurity.InitializeDatabaseConnection("NekiNamespace.DataEntities", "Clients", "ClientId", "Email", autoCreateTables: true);

znaci DataEntities je moj DataContext, Clients je naziv klase/tablice, ClientID je primarni ključ, Email je username polje.
Ova metoda kreira tablicu (bas okine CREATE TABLE sql) sa ClientId i Email kolonama, a ako imate jos nekae not-nullable kolone (npr unutar klase Client imate neki int property, a ne Nullabe ili int?), onda ce ovo baciti gresku. Da bi kreirali punu Clients tablicu sa svim kolonama iz Client klase, potrebno je izmjeniti Register metodu u AccountsController klasi (ona sa HttpPost atributom), u ovo:

WebSecurity.CreateUserAndAccount(model.UserName, model.Password, new { NekiNotNullProp = 0, NekiNotNullProp2 = 0, IsActive = true  });

ovaj anonimni objekt kao zadnji parametar govori SimpleMembProvideru da kreira i navedene kolone i postavi im ispravni tip. Time se EF 4/5 i SimpleMembProvider nece potuc oko toga tko kreira koje tablice u bazi.

I da, ovo je potrebno ako EF kreira bazu, odnosno ako koristite neki od db initializera koji se definira u global.asax-u, npr:

Database.SetInitializer(new CreateDatabaseIfNotExists<DataEntities>());

Iskreno, ne svidja mi se kako to WebSecurity klasa radi, jer je dosta zatvorena i rucno kreira i okida SQL, ali barem se moze nekako overrideati … Nadam se, sada kada je cijeli ovaj framework Open Source, da ce doci do određenih poboljsanja i refactoringa.

Da slažem se s tobom, dosta je zatvoren i nemaš baš nekih velikih mogučnosti. Ja sam pristupio tome malo drugčije. Onaj defaultni DbContext koji dođe s predloškom koji kreira UserProfile tablicu, e taj context sam izbacio i dodao tu tablicu u svoj context na app level razini, nakon toga možeš u Userptofile klasu dodati i sva ostala polja koja ti trebaju, ja za sada imam ovo, a s obzirom na migracije koje su dodane nemaš problema sa upgradeom tablice kasnije, ovako trenutno izgleda defaultni UserProfile class nakon mojih izmjena:

  [Table("UserProfile")]
    public class UserProfile
    {

        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int UserId { get; set; }
        public string UserName { get; set; }
        public string UserEmail { get; set; }
        public string UserBio { get; set; }
        public string UserImageUrl { get; set; }

        public Decimal? UserRating { get; set; }
        public UserStatus UserStatus { get; set; }

        public virtual ICollection<Review> Reviews { get; set; }
    }

E sad da bi to radilo morao sam odraditi još neke stvari, so bzirom da mi treba app level authentication i trebaju mi još neke stvari vezane uz security onaj filter koji se nalazi u AccountController (InitializeSimpleMembershipAttribute) ja sam prebacio u App-Start/FilterConfig.cs
pa mi taj file sad trenutno izgleda ovako:

    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
            filters.Add(new InitializeSimpleMembershipAttribute());
        }
    }

Sad imam pristup svim značajkama te klase u cijeloj aplikaciji bez instanciranja iste, a to je baš ono što mi je trebalo.Osim toga sad mogu jednostavno napraviti ovo:

  public class Review
    {
        public int ReviewId { get; set; }
        public int UserId { get; set; }

        public DateTime ReviewCreatedOn { get; set; }

        public string ReviewTitle { get; set; }
        public string ReviewBody { get; set; }

        [B]public virtual UserProfile User { get; set; }[/B]

        public Boolean ReviewPublished { get; set; }
        public Boolean ReviewFeatured { get; set; }

        public ReviewStatus ReviewStatus { get; set; }
        public virtual ICollection<Vote> Votes { get; set; }

        public virtual ICollection<Comment> Comments { get; set; }

        public virtual ICollection<Tag> Tags { get; set; }

        public virtual ICollection<Category> Categories { get; set; }
    }

Primejti boldano, mogu se lagano povezati s Userprofilom i raditi s njime što me volja, a s druge strane, nemam potrebu raditi svoju klasu za autentifikaciju i autorizaciju jer sve ostalo radi sasvim normalno. Jedino ostalo što sam izmejnio je to da sam u InitializeSimpleMembershipAttribute.cs datoteci izmjenio connectionstring u funkciji InitialDatabaseConnection pa ona sad izgleda ovako:

WebSecurity.InitializeDatabaseConnection("AppConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);

Eto nadam se da sam pokazao i malo drugčiji pristup od tvoga, ali i jedan idrugi su sasvim OK. A ono uvijek je dobro imati više opcija.

To je to sta sam ja napravio, ali desavalo se da kada je WebSecurity (SimpleMembProv) kreirao UserProfile, tablica bi imala samo dvije kolone: UserID i Email. Zato sam trebao dodati onoj anonimni objekt kao parametar u AccountsControlleru.

Pa i meni se to dešavalo po defaultu, ali kad sam ovo napravio i dodao nove kolone u userprofile tablicu, bez problema je sve kreirao i radi s njima ko da su od početka tu. Jedina razlika između mog i tvog pristupa je izgleda samo potreba za anonimnim objektom. Ali enma veze bitno da nam radi obojima. :slight_smile:

BTW. Ima li kakvog posla kod vas u Rijeci?

Bas cu probati ovaj tvoj pristup, mozda sam nepotrebno zakomplicirao :slight_smile:

Uglavnom, drago mi je da su dodali face, twitter i google autentikaciju unutar mvc predloska, jednostavno i brzo se dobije sva potrebna funkcionalnost, i sto su u bazu samo 3-4 dodatne tablice, a ne kao prije kod SqlMembProvidera, gdje bi ovaj dodao brdo tablica, viewova, store procedura.

Za svoj projekt sa doslovno uzeo AccountController i samo nakeljio svoje View-ove, sve gotovo kroz par sati podesavanja htmla i cssa.

:slight_smile:

Da i meni je to bilo prvi put tako, kad sam otvorio ono što je on tamo odradio i kreirao, “zasro” sam se od straha s pitanjem u glavi “A koji k…c je to sad”. Ovo mi s ečini mnogo jednostavnije i elegantnije riješeno, a o fb, twitter, google autentikaciji da i ne govorim, sinula mi je ideja i prvo što sam išao progooglati je integracija tih sustava autentikacije u asp.net mvc aplikaciju, kad ono tamo već sve gotovo. Odlično su to odradili.

Istina, nevjerojatno mi je da suvislu aplikaciju možeš složiti za samo par sati, a da pritom imaš sve moguće opcije nadogradnje kasnije, bez potrebe za nekim refactoringom i sl. sranjima, a pritom imaš sve moguće već odrađeno. Mislim da ovaj Membership provider može poslužiti iu mnogo ozbiljnijim aplikacijama, rekao bih enterpris level stvarima, bez potrebe za nekom velikom modifikacijom ili izgradnjom iste iz nule, a super mi je i to što istu tablicu možeš koristiti i za više aplikacija, a ne za samo jednu. Bar s nadam da je tako ostalo. :slight_smile:

E nije ostalo. baš gledam strukturu tablica i vidim da se nigdje ne spominje ApplicationId iako mislim da to nebi trebao biti problem uz koji override, :slight_smile: