<option value="value">Name</option>
.attr("value", data[i].Id).text(data[i].Title)
<option value="100">AmirHossein</option>
<option value="value">Name</option>
.attr("value", data[i].Id).text(data[i].Title)
<option value="100">AmirHossein</option>
در Blazor میتوان مسیریابیهای پارامتری را به صورت زیر نیز تعریف کرد:
@page "/post/edit/{EditId:int}"
که در اینجا EditId، یک پارامتر مسیریابی از نوع int تعریف شده و به صورت زیر در کدهای صفحهی مرتبط، قابل دسترسی است:
[Parameter] public int? EditId { set; get; }
int تعریف شدهی در این مسیریابی، یک routing constraint و یا یک قید مسیریابی محسوب میشود و استفادهی از آن، چنین مزایایی را به همراه دارد:
- در این حالت فقط EditId های عددی پردازش میشوند و اگر رشتهای دریافت شود، کاربر با خروجی از نوع 404 و یا «یافت نشد»، مواجه خواهد شد.
- امکان اعتبارسنجی مقادیر دریافتی، پیش از ارسال آنها به صفحه و پردازش صفحه.
قیود پیشفرض تعریف شدهی در Blazor
اگر به مستندات مسیریابی Blazor مراجعه کنیم، بهنظر فقط این موارد را میتوان بهعنوان قیود پارامترهای مسیریابی تعریف کرد:
bool, datetime, decimal, double, float, guid, int, long, nonfile
و ... توضیحاتی در مورد اینکه آیا امکان بسط آنها وجود دارند یا خیر، فعلا در مستندات رسمی آن، ذکر نشدهاند.
در Blazor 8x میتوان از قیود مسیریابی سفارشی ASP.NET Core نیز استفاده کرد!
ASP.NET Core سمت سرور، به همراه امکان سفارشی سازی قیودمسیریابی خود نیز هست که آنرا میتوان به کمک اینترفیسIRouteConstraint پیاده سازی کرد:
namespace Microsoft.AspNetCore.Routing { public interface IRouteConstraint { bool Match( HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection); } }
جالب اینجا است که میتوان این نمونههای سفارشی را حداقل در نگارش جدید Blazor 8x SSR نیز استفاده کرد؛ هرچند در مستندات رسمی Blazor هنوز به آن اشارهای نشدهاست.
در امضای متد Match فوق، دو پارامتر routeKey و values آن بیش از مابقی مهم هستند:
- routeKey مشخص میکند که الان کدام پارامتر مسیریابی (مانند EditId در این مطلب) در حال پردازش است.
- values، یک دیکشنری است که کلید هر عضو آن، پارامتر مسیریابی و مقدار آن، مقدار دریافتی از URL جاری است.
- اگر این متد مقدار true را برگرداند، یعنی مسیریابی وارد شدهی به آن، با موفقیت پردازش و اعتبارسنجی شده و میتوان صفحهی مرتبط را نمایش داد؛ در غیراینصورت، کاربر پیام یافت نشدن آن صفحه و مسیر درخواستی را مشاهده میکند.
پیاده سازی یک قید سفارشی رمزگشایی پارامترهای مسیریابی
فرض کنید قصد ندارید که پارامترهای مسیریابی ویرایش رکوردهای خاصی را دقیقا بر اساس Id متناظر عددی آنها در بانک اطلاعاتی، نمایش دهید؛ برای مثال نمیخواهید دقیقا آدرس post/edit/1 را به کاربر نمایش دهید؛ چون نمایش این اعداد عموما ساده و ترتیبی، حدس زدن آنها را ساده کرده و ممکن است در آینده مشکلات امنیتی را به همراه داشته باشد.
میخواهیم از آدرسهای متداول و سادهی عددی زیر:
@page "/post/edit/{EditId:int}"
به آدرس رمزنگاری شدهی زیر برسیم:
@page "/post/edit/{EditId:encrypt}"
اگر به این آدرس جدید دقت کنید، در اینجا از نام قید جدیدی به نام encrypt استفاده شدهاست که جزو قیود پیشفرض سیستم مسیریابی Blazor نیست. روش تعریف آن به صورت زیر است:
using System.Globalization; using DNTCommon.Web.Core; namespace Blazor8xSsrComponents.Utils; public class EncryptedRouteConstraint(IProtectionProviderService protectionProvider) : IRouteConstraint { public const string Name = "encrypt"; public bool Match(HttpContext? httpContext, IRouter? route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { ArgumentNullException.ThrowIfNull(routeKey); ArgumentNullException.ThrowIfNull(values); if (!values.TryGetValue(routeKey, out var routeValue)) { return false; } var valueString = Convert.ToString(routeValue, CultureInfo.InvariantCulture); values[routeKey] = string.IsNullOrEmpty(valueString) ? null : protectionProvider.Decrypt(valueString); return true; } }
توضیحات:
- در قیود سفارشی میتوان سرویسها را به سازندهی کلاس تزریق کرد و برای مثال از سرویس IProtectionProviderService که در کتابخانهی DNTCommon.Web.Core تعریف شده، برای رمزگشایی اطلاعات رسیده، استفاده کردهایم.
- یک نام را هم برای آن درنظر گرفتهایم که از این نام در فایل Program.cs به صورت زیر استفاده میشود:
builder.Services.Configure<RouteOptions>(opt => { opt.ConstraintMap.Add(EncryptedRouteConstraint.Name, typeof(EncryptedRouteConstraint)); });
یعنی زمانیکه سیستم مسیریابی به قید جدیدی به نام encrypt میرسد:
@page "/post/edit/{EditId:encrypt}"
آنرا در لیست ConstraintMap ای که به نحو فوق به سیستم معرفی شده، جستجو میکند. اگر این نام یافت شد، سپس کلاس EncryptedRouteConstraint متناظر را نمونه سازی کرده و در جهت پردازش مسیر رسیده، مورد استفاده قرار میدهد.
- در کلاس EncryptedRouteConstraint و متد Match آن، مقدار رشتهای EditId دریافت شدهی از طریق آدرس جاری درخواستی، رمزگشایی شده و بجای مقدار فعلی رمزنگاری شدهی آن درج میشود. همین اندازه برای مقدار دهی خودکار پارامتر EditId ذیل در صفحات مرتبط، کفایت میکند:
[Parameter] public string? EditId { set; get; }
یعنی دیگر نیازی نیست تا در صفحات مرتبط، کار رمزگشایی EditId، به صورت دستی انجام شود.
npm install ng2-slim-loading-bar --save
"styles": [ "../node_modules/ng2-slim-loading-bar/style.css", "styles.css" ],
import {SlimLoadingBarModule} from 'ng2-slim-loading-bar'; @NgModule({ imports: [ //... SlimLoadingBarModule.forRoot() ] }) export class AppModule { }
import {SlimLoadingBarService} from 'ng2-slim-loading-bar';
<ng2-slim-loading-bar></ng2-slim-loading-bar>
ng g s core/interceptors/LoaderInterceptor --spec false
import { Injectable } from "@angular/core"; import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from "@angular/common/http"; import { Observable } from "rxjs/Observable"; import "rxjs/add/operator/do"; import { SlimLoadingBarService } from "ng2-slim-loading-bar"; @Injectable() export class LoaderInterceptorService implements HttpInterceptor { constructor(private loadingBar: SlimLoadingBarService) { } intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // start our loader here this.loadingBar.start(); return next.handle(req).do( (event: HttpEvent<any>) => { if (event instanceof HttpResponse) { this.loadingBar.complete(); } }, (err: any) => { this.loadingBar.complete(); }); } }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
@NgModule({ providers: [ { provide: HTTP_INTERCEPTORS, useClass: LoaderInterceptorService, multi: true } ] }) export class AppModule {}
PM> Install-Package jquery.mobile
<meta name="viewport" content="width=device-width">
<head> <meta name="viewport" content="width=device-width,initial-sclae=1" /> <link href="Content/jquery.mobile-1.1.0.css" rel="stylesheet" type="text/css" /> <script src="Scripts/jquery-1.6.4.js" type="text/javascript"></script> <script src="Scripts/jquery.mobile-1.1.0.js" type="text/javascript"></script> <title></title> </head> <body> <div data-role="page"> <div data-role="header" data-theme="b"> <h1>this is a test </h1> </div> <div data-role="conent"> <ul data-role="listview" data-filter="true" data-inset="true" data-theme="e"> <li><a href="#">Water</a></li> <li><a href="#">Pepsi</a></li> <li><a href="#">Diet Pepsi</a></li> <li><a href="#">Beer</a></li> <a href="#" data-role="button" data-theme="b">Click ME</a> </ul> </div> <div data-role="footer" data-theme="b" data-position="fixed"> <h1>footer </h1> </div> </div> </body>
data-role="page"
" data-role="header
"data-theme="e
"data-role="listview
"data-filter="true
" data-inset="true"
• Which API are you using? – Google+ API • Where will you be calling the API from? – Web server (e.g. node.js, Tomcat) • What data will you be accessing? – User data
https://localhost:6001/signin-google
{ "Authentication": { "Google": { "ClientId": "xxxx", "ClientSecret": "xxxx" } } }
namespace DNT.IDP { public class Startup { public void ConfigureServices(IServiceCollection services) { // ... services.AddAuthentication() .AddGoogle(authenticationScheme: "Google", configureOptions: options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; options.ClientId = Configuration["Authentication:Google:ClientId"]; options.ClientSecret = Configuration["Authentication:Google:ClientSecret"]; }); }
public const string ExternalCookieAuthenticationScheme = "idsrv.external";
namespace DNT.IDP.Controllers.Account { [SecurityHeaders] [AllowAnonymous] public class ExternalController : Controller { public async Task<IActionResult> Callback() { var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme); var returnUrl = result.Properties.Items["returnUrl"] ?? "~/"; var (user, provider, providerUserId, claims) = await FindUserFromExternalProvider(result); if (user == null) { // user = AutoProvisionUser(provider, providerUserId, claims); var returnUrlAfterRegistration = Url.Action("Callback", new { returnUrl = returnUrl }); var continueWithUrl = Url.Action("RegisterUser", "UserRegistration" , new { returnUrl = returnUrlAfterRegistration, provider = provider, providerUserId = providerUserId }); return Redirect(continueWithUrl); }
var (user, provider, providerUserId, claims) = await FindUserFromExternalProvider(result); foreach (var claim in claims) { _logger.LogInformation($"External provider[{provider}] info-> claim:{claim.Type}, value:{claim.Value}"); }
External provider[Google] info-> claim:http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name, value:Vahid N. External provider[Google] info-> claim:http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname, value:Vahid External provider[Google] info-> claim:http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname, value:N. External provider[Google] info-> claim:urn:google:profile, value:https://plus.google.com/105013528531611201860 External provider[Google] info-> claim:http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress, value:my.name@gmail.com
[HttpGet] public async Task<IActionResult> Callback() { // ... var (user, provider, providerUserId, claims) = await FindUserFromExternalProvider(result); if (user == null) { // user wasn't found by provider, but maybe one exists with the same email address? if (provider == "Google") { // email claim from Google var email = claims.FirstOrDefault(c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"); if (email != null) { var userByEmail = await _usersService.GetUserByEmailAsync(email.Value); if (userByEmail != null) { // add Google as a provider for this user await _usersService.AddUserLoginAsync(userByEmail.SubjectId, provider, providerUserId); // redirect to ExternalLoginCallback var continueWithUrlAfterAddingUserLogin = Url.Action("Callback", new {returnUrl = returnUrl}); return Redirect(continueWithUrlAfterAddingUserLogin); } } } var returnUrlAfterRegistration = Url.Action("Callback", new {returnUrl = returnUrl}); var continueWithUrl = Url.Action("RegisterUser", "UserRegistration", new {returnUrl = returnUrlAfterRegistration, provider = provider, providerUserId = providerUserId}); return Redirect(continueWithUrl); }
using Microsoft.AspNetCore.Mvc; namespace AngularTemplateDrivenFormsLab.Controllers { [Route("api/[controller]")] public class ShowImagesController : Controller { [HttpGet("[action]")] public IActionResult GetImage() { return File("~/assets/resume.png", "image/png"); } } }
import { Injectable } from "@angular/core"; import { Observable } from "rxjs/Observable"; import { HttpClient } from "@angular/common/http"; @Injectable() export class DownloadBinaryDataService { constructor(private httpClient: HttpClient) { } public getImage(): Observable<Blob> { return this.httpClient.get("/api/ShowImages/GetImage", { responseType: "blob" }); } }
import { Injectable } from "@angular/core"; function getWindow(): any { return window; } @Injectable() export class WindowRefService { get nativeWindow(): any { return getWindow(); } }
import { WindowRefService } from "./window.service"; @NgModule({ providers: [ WindowRefService ] }) export class CoreModule {}
const urlCreator = this.nativeWindow.URL; imageBlobUrl = urlCreator.createObjectURL(imageDataBlob);
<img src="blob:http://localhost:5000/9d4bae44-00bc-4ed8-9f27-cac2de5ecd5d">
img-src 'self' data: blob:
import { WindowRefService } from "./../../core/window.service"; import { DownloadBinaryDataService } from "app/angular-http-client-blob/download-binary-data.service"; import { Component, OnInit, ViewChild, ElementRef } from "@angular/core"; import { DomSanitizer, SafeUrl } from "@angular/platform-browser"; @Component({ templateUrl: "./download-blobs.component.html", styleUrls: ["./download-blobs.component.css"] }) export class DownloadBlobsComponent implements OnInit { @ViewChild("sampleImage1") sampleImage1: ElementRef; private nativeWindow: Window; imageBlobUrl: string; sanitizedImageBlobUrl: SafeUrl; constructor(private downloadService: DownloadBinaryDataService, private windowRefService: WindowRefService, private sanitizer: DomSanitizer) { } ngOnInit() { this.nativeWindow = this.windowRefService.nativeWindow; this.downloadService.getImage().subscribe(imageDataBlob => { const urlCreator = this.nativeWindow.URL; this.imageBlobUrl = urlCreator.createObjectURL(imageDataBlob); // doesn't work -> <img [src]="imageBlobUrl"> this.sampleImage1.nativeElement.src = this.imageBlobUrl; // works -> <img #sampleImage1> this.sanitizedImageBlobUrl = this.sanitizer.bypassSecurityTrustUrl(this.imageBlobUrl); // works -> <img [src]="sanitizedImageBlobUrl"> }); } }
<h1>Angular HttpClient Blob</h1> <h4>#sampleImage1</h4> <img #sampleImage1> <h4>imageBlobUrl</h4> <img [src]="imageBlobUrl"> <h4>sanitizedImageBlobUrl</h4> <img [src]="sanitizedImageBlobUrl">
this.imageBlobUrl = urlCreator.createObjectURL(imageDataBlob); // doesn't work -> <img [src]="imageBlobUrl">
<h4>imageBlobUrl</h4> <img [src]="imageBlobUrl">
<img _ngcontent-c1="" src="unsafe:blob:http://localhost:5000/a4505339-5da2-4303-949c-8e6a7cfff2fc">
Refused to load the image 'unsafe:blob:http://localhost:5000/a4505339-5da2-4303-949c-8e6a7cfff2fc' because it violates the following Content Security Policy directive: "img-src 'self' data: blob:".
this.sanitizedImageBlobUrl = this.sanitizer.bypassSecurityTrustUrl(this.imageBlobUrl); // works -> <img [src]="sanitizedImageBlobUrl">
<img [src]="sanitizedImageBlobUrl">
<img _ngcontent-c1="" src="blob:http://localhost:5000/a4505339-5da2-4303-949c-8e6a7cfff2fc">
<img #sampleImage1>
@ViewChild("sampleImage1") sampleImage1: ElementRef;
this.sampleImage1.nativeElement.src = this.imageBlobUrl; // works -> <img #sampleImage1>
<ng-component _nghost-c1=""><h1 _ngcontent-c1="">Angular HttpClient Blob</h1> <h4 _ngcontent-c1="">#sampleImage1</h4> <img _ngcontent-c1="" src="blob:http://localhost:5000/a4505339-5da2-4303-949c-8e6a7cfff2fc"> <h4 _ngcontent-c1="">imageBlobUrl</h4> <img _ngcontent-c1="" src="unsafe:blob:http://localhost:5000/a4505339-5da2-4303-949c-8e6a7cfff2fc"> <h4 _ngcontent-c1="">sanitizedImageBlobUrl</h4> <img _ngcontent-c1="" src="blob:http://localhost:5000/a4505339-5da2-4303-949c-8e6a7cfff2fc"> </ng-component>
using System;
using System.IO;
namespace NHibernate.Helper.DbSpecific
{
public class SqlCEDbHelper
{
const string engineTypeName = "System.Data.SqlServerCe.SqlCeEngine, System.Data.SqlServerCe";
/// <summary>
/// note: this method will delete existing db and then creates a new one.
/// </summary>
/// <param name="filename"></param>
/// <param name="password"></param>
public static void CreateEmptyDatabaseFile(string filename, string password = "")
{
if (File.Exists(filename))
File.Delete(filename);
var type = System.Type.GetType(engineTypeName);
var localConnectionString = type.GetProperty("LocalConnectionString");
var createDatabase = type.GetMethod("CreateDatabase");
var engine = Activator.CreateInstance(type);
string connectionStr = string.Format("Data Source='{0}';Password={1};Encrypt Database=True", filename, password);
if (string.IsNullOrWhiteSpace(password))
connectionStr = string.Format("Data Source='{0}'", filename);
localConnectionString.SetValue(
obj: engine,
value: connectionStr,
index: null);
createDatabase.Invoke(engine, new object[0]);
}
/// <summary>
/// use this method to compact or encrypt existing db or decrypt it to a new db with all records
/// </summary>
/// <param name="sourceConnection"></param>
/// <param name="destConnection"></param>
public static void CompactDatabase(string sourceConnection, string destConnection)
{
var type = System.Type.GetType(engineTypeName);
var engine = Activator.CreateInstance(type);
var localConnectionString = type.GetProperty("LocalConnectionString");
localConnectionString.SetValue(
obj: engine,
value: sourceConnection,
index: null);
var compactDatabase = type.GetMethod("Compact");
compactDatabase.Invoke(engine, new object[] { destConnection });
}
}
}
Data Source=c:\path\db.sdf;Password=1234;Encrypt Database=True
private Configuration getConfig()
{
var configure = new Configuration();
configure.SessionFactoryName("BuildIt");
configure.DataBaseIntegration(db =>
{
db.ConnectionProvider<DriverConnectionProvider>();
db.Dialect<MsSqlCe40Dialect>();
db.Driver<SqlServerCeDriver>();
db.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
db.IsolationLevel = IsolationLevel.ReadCommitted;
db.ConnectionString = ConnectionString;
db.Timeout = 10;
//for testing ...
db.LogFormattedSql = true;
db.LogSqlInConsole = true;
});
return configure;
}
[ResponseCache(Duration = 60)] public IActionResult Contact() { ViewData["Message"] = "Your contact page."; return View(); }
Cache-Control: public,max-age=60
[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Client)]
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { return View(); }
Cache-Control: no-store,no-cache Pragma: no-cache
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { options.CacheProfiles.Add("PrivateCache", new CacheProfile { Duration = 60, Location = ResponseCacheLocation.Client }); });
[ResponseCache(CacheProfileName = "PrivateCache")]
{ "dependencies": { //same as before "Microsoft.Extensions.Caching.Memory": "1.0.0" },
public void ConfigureServices(IServiceCollection services) { services.AddMemoryCache();
[Route("DNT/[controller]")] public class AboutController : Controller { private readonly IMemoryCache _memoryCache; public AboutController(IMemoryCache memoryCache) { _memoryCache = memoryCache; } [Route("")] public ActionResult Hello() { string cacheKey = "my-cache-key"; string greeting; if (!_memoryCache.TryGetValue(cacheKey, out greeting)) { greeting = "Hello"; // store in the cache _memoryCache.Set(cacheKey, greeting, new MemoryCacheEntryOptions() .SetAbsoluteExpiration(TimeSpan.FromMinutes(1))); } return Content($"{greeting} from DNT!"); }
new MemoryCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromMinutes(5))
new MemoryCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromMinutes(5)) .SetAbsoluteExpiration(TimeSpan.FromHours(1))
new MemoryCacheEntryOptions() .SetPriority(CacheItemPriority.NeverRemove))
<cache expires-after="@TimeSpan.FromMinutes(10)"> @Html.Partial("_WhatsNew") *last updated @DateTime.Now.ToLongTimeString() </cache>
<cache expires-after="@TimeSpan.FromSeconds(5)"> <!--View Component or something that gets data from the database--> *last updated @DateTime.Now.ToLongTimeString() </cache>
<cache expires-on="@DateTime.Today.AddDays(1).AddTicks(-1)"> <!--View Component or something that gets data from the database--> *last updated @DateTime.Now.ToLongTimeString() </cache>
<cache expires-sliding="@TimeSpan.FromMinutes(5)"> <!--View Component or something that gets data from the database--> *last updated @DateTime.Now.ToLongTimeString() </cache>
<cache vary-by-user="true"> <!--View Component or something that gets data from the database--> *last updated @DateTime.Now.ToLongTimeString() </cache>
<cache vary-by-route="id"> <!--View Component or something that gets data from the database--> *last updated @DateTime.Now.ToLongTimeString() </cache>
<cache vary-by-query="search"> <!--View Component or something that gets data from the database--> *last updated @DateTime.Now.ToLongTimeString() </cache>
<cache vary-by-cookie="MyAppCookie"> <!--View Component or something that gets data from the database--> *last updated @DateTime.Now.ToLongTimeString() </cache>
<cache vary-by-header="User-Agent"> <!--View Component or something that gets data from the database--> *last updated @DateTime.Now.ToLongTimeString() </cache>
<cache vary-by="@ViewBag.ProductId"> <!--View Component or something that gets data from the database--> *last updated @DateTime.Now.ToLongTimeString() </cache>
<cache vary-by-user="true" vary-by-route="id"> <!--View Component or something that gets data from the database--> *last updated @DateTime.Now.ToLongTimeString() </cache>
<cache expires-sliding="@TimeSpan.FromMinutes(10)" priority="@Microsoft.Extensions.Caching.Memory.CacheItemPriority.NeverRemove"> <!--View Component or something that gets data from the database--> *last updated @DateTime.Now.ToLongTimeString() </cache>
One or more validation errors were detected during model generation:
\tSystem.Data.Entity.Edm.EdmEntityType: : EntityType 'Blog' has no key defined.
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace EF_Sample01.Models
{
public class Blog
{
[Key]
public int MyTableKey { set; get; }
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace EF_Sample01.Models
{
public class Blog
{
[Key]
public int MyTableKey { set; get; }
[MaxLength(100)]
public string Title { set; get; }
[Required]
public string AuthorName { set; get; }
public IList<Post> Posts { set; get; }
}
}
CREATE TABLE [dbo].[Blogs](
[MyTableKey] [int] IDENTITY(1,1) NOT NULL,
[Title] [nvarchar](100) NULL,
[AuthorName] [nvarchar](max) NOT NULL,
CONSTRAINT [PK_Blogs] PRIMARY KEY CLUSTERED
(
[MyTableKey] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
[Required(ErrorMessage = "لطفا نام نویسنده را مشخص نمائید")]
public string AuthorName { set; get; }
using System.Data.Entity;
using EF_Sample01.Models;
namespace EF_Sample01
{
public class Context : DbContext
{
public DbSet<Blog> Blogs { set; get; }
public DbSet<Post> Posts { set; get; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>().HasKey(x => x.MyTableKey);
modelBuilder.Entity<Blog>().Property(x => x.Title).HasMaxLength(100);
modelBuilder.Entity<Blog>().Property(x => x.AuthorName).IsRequired();
base.OnModelCreating(modelBuilder);
}
}
}
using System.Data.Entity;
using EF_Sample01.Models;
using System.Data.Entity.ModelConfiguration;
namespace EF_Sample01
{
public class BlogConfig : EntityTypeConfiguration<Blog>
{
public BlogConfig()
{
this.Property(x => x.Id).HasColumnName("MyTableKey");
this.Property(x => x.RowVersion).HasColumnType("Timestamp");
}
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new BlogConfig());
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace EF_Sample01.Models
{
[Table("tblBlogs")]
public class Blog
{
[Column("MyTableKey")]
public int Id { set; get; }
[MaxLength(100)]
public string Title { set; get; }
[Required(ErrorMessage = "لطفا نام نویسنده را مشخص نمائید")]
public string AuthorName { set; get; }
public IList<Post> Posts { set; get; }
[Timestamp]
public byte[] RowVersion { set; get; }
}
}
modelBuilder.Entity<Blog>().ToTable("tblBlogs");
modelBuilder.Entity<Blog>().Property(x => x.Id).HasColumnName("MyTableKey");
modelBuilder.Entity<Blog>().Property(x => x.RowVersion).HasColumnType("Timestamp");
System.Data.Entity.Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Context>());
// or
System.Data.Entity.Database.SetInitializer(new DropCreateDatabaseAlways<Context>());
public class MyInitializer : IDatabaseInitializer<Context>
{
public void InitializeDatabase(Context context)
{
if (context.Database.Exists() ||
context.Database.CompatibleWithModel(throwIfNoMetadata: false))
context.Database.Delete();
context.Database.Create();
}
}
System.Data.Entity.Database.SetInitializer(new MyInitializer());
Database.SetInitializer<Context>(null);
<appSettings>
<add key="DatabaseInitializerForType MyNamespace.MyDbContextClass, MyAssembly"
value="MyNamespace.MyInitializerClass, MyAssembly" />
</appSettings>
<appSettings>
<add key="DatabaseInitializerForType MyNamespace.MyDbContextClass, MyAssembly"
value="Disabled" />
</appSettings>
<appSettings>
<add key="DatabaseInitializerForType EF_Sample01.Context, EF_Sample01"
value="EF_Sample01.MyInitializer, EF_Sample01" />
</appSettings>
public class MyCustomInitializer : DropCreateDatabaseIfModelChanges<Context>
{
protected override void Seed(Context context)
{
context.Blogs.Add(new Blog { AuthorName = "Vahid", Title = ".NET Tips" });
context.Database.ExecuteSqlCommand("CREATE INDEX IX_title ON tblBlogs (title)");
base.Seed(context);
}
}
Server=(local);Database=yourDatabase;User ID=yourDBUser;Password=yourDBPassword;Trusted_Connection=False;Persist Security Info=True
[Table("tblBlogs", Schema="someUser")]
public class Blog
modelBuilder.Entity<Blog>().ToTable("tblBlogs", schemaName:"someUser");