یه ازای همه کلاس ها باید اینترفیس تعریف کنیم؟
(حتی واسه گوگل کلمه MVP تازه است به طوری که did you mean... گوگل کلمه MVC رو پیشنهاد میکنه!)
{ path: 'products', loadChildren:'app/product/product.module#ProductModule' },
const routes: Routes = [ { path: 'home', component: WelcomeComponent }, { path: 'welcome', redirectTo: 'home', pathMatch: 'full' }, { path: 'products', loadChildren: 'app/product/product.module#ProductModule' }, { path: '', redirectTo: 'home', pathMatch: 'full' }, { path: '**', component: PageNotFoundComponent } ];
chunk {0} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 165 kB {4} [initial] chunk {1} main.bundle.js, main.bundle.js.map (main) 32.7 kB {3} [initial] [rendered] chunk {2} styles.bundle.js, styles.bundle.js.map (styles) 129 kB {4} [initial] chunk {3} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.72 MB [initial] [rendered] chunk {4} inline.bundle.js, inline.bundle.js.map (inline) 0 bytes [entry] chunk {5} 5.chunk.js, 5.chunk.js.map 51.1 kB {1} [rendered]
const routes: Routes = [ { path: 'products', canActivate: [ AuthGuard ], children: [ ] } ];
import { AuthGuard } from './user/auth.guard'; const routes: Routes = [ { path: 'home', component: WelcomeComponent }, { path: 'welcome', redirectTo: 'home', pathMatch: 'full' }, { path: 'products', loadChildren: 'app/product/product.module#ProductModule', canActivate: [AuthGuard] }, { path: '', redirectTo: 'home', pathMatch: 'full' }, { path: '**', component: PageNotFoundComponent } ];
const routes: Routes = [ { path: '', component: ProductListComponent }, { path: ':id', component: ProductDetailComponent, resolve: { product: ProductResolverService } }, { path: ':id/edit', component: ProductEditComponent, resolve: { product: ProductResolverService }, canDeactivate: [ProductEditGuard], children: [ { path: '', redirectTo: 'info', pathMatch: 'full' }, { path: 'info', component: ProductEditInfoComponent }, { path: 'tags', component: ProductEditTagsComponent } ] } ];
import { ActivatedRouteSnapshot, RouterStateSnapshot, CanActivate, Router, CanLoad, Route } from '@angular/router'; @Injectable() export class AuthGuard implements CanActivate, CanLoad { canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { return this.checkLoggedIn(state.url); } canLoad(route: Route): boolean { return this.checkLoggedIn(route.path); } // … the same as before }
{ path: 'products', loadChildren: 'app/product/product.module#ProductModule', canLoad: [AuthGuard] },
import { Routes, RouterModule, PreloadAllModules } from '@angular/router'; @NgModule({ imports: [RouterModule.forRoot( routes, { enableTracing: true, preloadingStrategy: PreloadAllModules /*, useHash: true*/ } )],
>ng g s SelectiveStrategy -m app.module
installing service create src\app\selective-strategy.service.spec.ts create src\app\selective-strategy.service.ts update src\app\app.module.ts
import { Injectable } from '@angular/core'; import { Route, PreloadingStrategy } from '@angular/router'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/of'; @Injectable() export class SelectiveStrategyService implements PreloadingStrategy { preload(route: Route, load: Function): Observable<any> { if (route.data && route.data['preload']) { return load(); } return Observable.of(null); } }
import { SelectiveStrategyService } from './selective-strategy.service'; @NgModule({ imports: [RouterModule.forRoot( routes, { enableTracing: true, preloadingStrategy: SelectiveStrategyService /*, preloadingStrategy: PreloadAllModules*/ /*, useHash: true*/ } )],
{ path: 'products', loadChildren: 'app/product/product.module#ProductModule', //canLoad: [AuthGuard] canActivate: [AuthGuard], data: { preload: true } },
بهترین روش یادگیری برنامه نویسی انجام پروژههای مختلف هست.
وب سایت معرفی شده در لینک بالا اومده کلون clone بیشتر از ۱۰۰ وبسایت بزرگ مثل آمازون، نتفیلیکس، یوتیوب، تیک تاک، سرویسهای گوگل، پروژه واتساپ و ... را به صورت اوپن سورس به همراه تمام اطلاعات از جمله چه زبان برنامه نویسی و تکنولوژیهایی استفاده کردند، لینک دمو و گیت هاب را گذاشته.
بهترین منبع برای اینکه یادبگیرید یه وب سایت پیچیده چطور درست شده، چطوری سیستمها طراحی شدند و الی آخر.
PM> Install-Package DNTFrameworkCore -Version 1.0.0 PM> Install-Package DNTFrameworkCore.EntityFramework -Version 1.0.0
[LocalizationResource(Name = "SharedResource", Location = "DNTFrameworkCore.TestAPI")] public class BlogModel : MasterModel<int>, IValidatableObject { public string Title { get; set; } [MaxLength(50, ErrorMessage = "Maximum length is 50")] public string Url { get; set; } public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { if (Title == "BlogTitle") { yield return new ValidationResult("IValidatableObject Message", new[] {nameof(Title)}); } } }
public class BlogValidator : FluentModelValidator<BlogModel> { public BlogValidator(IMessageLocalizer localizer) { RuleFor(b => b.Title).NotEmpty() .WithMessage(localizer["Blog.Fields.Title.Required"]); } }
public class BlogValidator : ModelValidator<BlogkModel> { public override IEnumerable<ModelValidationResult> Validate(BlogModel model) { yield return new ModelValidationResult(nameof(BlogkModel.Title), "Validation from IModelValidator"); } }
public interface IBlogService : ICrudService<int, BlogModel> { }
public class BlogService : CrudService<Blog, int, BlogModel>, IBlogService { public BlogService(CrudServiceDependency dependency) : base(dependency) { } protected override IQueryable<BlogModel> BuildReadQuery(FilteredPagedQueryModel model) { return EntitySet.AsNoTracking().Select(b => new BlogModel {Id = b.Id, RowVersion = b.RowVersion, Url = b.Url, Title = b.Title}); } protected override Blog MapToEntity(BlogModel model) { return new Blog { Id = model.Id, RowVersion = model.RowVersion, Url = model.Url, Title = model.Title, NormalizedTitle = model.Title.ToUpperInvariant() //todo: normalize based on your requirement }; } protected override BlogModel MapToModel(Blog entity) { return new BlogModel { Id = entity.Id, RowVersion = entity.RowVersion, Url = entity.Url, Title = entity.Title }; } }
[LocalizationResource(Name = "SharedResource", Location = "DNTFrameworkCore.TestAPI")] public class TaskModel : MasterModel<int>, IValidatableObject { public string Title { get; set; } [MaxLength(50, ErrorMessage = "Validation from DataAnnotations")] public string Number { get; set; } public string Description { get; set; } public TaskState State { get; set; } = TaskState.Todo; public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { if (Title == "IValidatableObject") { yield return new ValidationResult("Validation from IValidatableObject"); } } }
public class TaskReadModel : MasterModel<int> { public string Title { get; set; } public string Number { get; set; } public TaskState State { get; set; } = TaskState.Todo; public DateTimeOffset CreationDateTime { get; set; } public string CreatorUserDisplayName { get; set; } }
public class TaskValidator : ModelValidator<TaskModel> { public override IEnumerable<ModelValidationResult> Validate(TaskModel model) { if (!Enum.IsDefined(typeof(TaskState), model.State)) { yield return new ModelValidationResult(nameof(TaskModel.State), "Validation from IModelValidator"); } } }
public interface ITaskService : ICrudService<int, TaskReadModel, TaskModel, TaskFilteredPagedQueryModel> { }
public class TaskFilteredPagedQueryModel : FilteredPagedQueryModel { public TaskState? State { get; set; } }
پیاده سازی واسط ITaskService با استفاده از AutoMapper
public class TaskService : CrudService<Task, int, TaskReadModel, TaskModel, TaskFilteredPagedQueryModel>, ITaskService { private readonly IMapper _mapper; public TaskService(CrudServiceDependency dependency, IMapper mapper) : base(dependency) { _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); } protected override IQueryable<TaskReadModel> BuildReadQuery(TaskFilteredPagedQueryModel model) { return EntitySet.AsNoTracking() .WhereIf(model.State.HasValue, t => t.State == model.State) .ProjectTo<TaskReadModel>(_mapper.ConfigurationProvider); } protected override Task MapToEntity(TaskModel model) { return _mapper.Map<Task>(model); } protected override TaskModel MapToModel(Task entity) { return _mapper.Map<TaskModel>(entity); } }
به عنوان مثال در کلاس بالا برای نگاشت مابین مدل و موجودیت، از واسط IMapper کتابخانه AutoMapper استفاده شدهاست و همچنین عملیات جستجوی سفارشی در همان متد BuildReadQuery برای تولید کوئری متد Read پیشفرض، قابل ملاحظه میباشد.
مثال سوم: پیادهسازی سرویس یک موجودیت اصلی به همراه تعدادی موجودیت فرعی وابسته (سناریوهای Master-Detail)
گام اول: طراحی Modelهای متناظر
public class UserModel : MasterModel { public string UserName { get; set; } public string DisplayName { get; set; } public string Password { get; set; } public bool IsActive { get; set; } public ICollection<UserRoleModel> Roles { get; set; } = new HashSet<UserRoleModel>(); public ICollection<PermissionModel> Permissions { get; set; } = new HashSet<PermissionModel>(); public ICollection<PermissionModel> IgnoredPermissions { get; set; } = new HashSet<PermissionModel>(); }
مدل بالا متناظر است با موجودیت کاربر سیستم، که به یکسری گروه کاربری متصل میباشد و همچنین دارای یکسری دسترسی مستقیم بوده و یا یکسری دسترسی از او گرفته شدهاست. مدلهای Detail نیز از قرارداد خاصی پیروی خواهند کرد که در ادامه مشاهده خواهیم کرد.
public class PermissionModel : DetailModel<int> { public string Name { get; set; } }
به عنوان مثال PermissionModel بالا از DetailModel جنریکای ارثبری کرده است که دارای Id و TrackingState نیز میباشد.
public class UserRoleModel : DetailModel<int> { public long RoleId { get; set; } }
شاید در نگاه اول برای گروههای کاربری یک کاربر کافی بود تا یک لیست ساده از long را از کلاینت دریافت کنیم. در این صورت نیاز است تا برای تمام موجودیتهای سیستم که چنین شرایط مشابهی را دارند، عملیات ثبت، ویرایش و حذف متناظر با تک تک Detailها را دستی مدیریت کنید. روش فعلی خصوصا برای سناریوهای منفصل به مانند پروژههای تحت وب، پیشنهاد میشود.
گام دوم: پیاده سازی اعتبارسنج مستقل
public class UserValidator : FluentModelValidator<UserModel> { private readonly IUnitOfWork _uow; public UserValidator(IUnitOfWork uow, IMessageLocalizer localizer) { _uow = uow ?? throw new ArgumentNullException(nameof(uow)); RuleFor(m => m.DisplayName).NotEmpty() .WithMessage(localizer["User.Fields.DisplayName.Required"]) .MinimumLength(3) .WithMessage(localizer["User.Fields.DisplayName.MinimumLength"]) .MaximumLength(User.MaxDisplayNameLength) .WithMessage(localizer["User.Fields.DisplayName.MaximumLength"]) .Matches(@"^[\u0600-\u06FF,\u0590-\u05FF,0-9\s]*$") .WithMessage(localizer["User.Fields.DisplayName.RegularExpression"]) .DependentRules(() => { RuleFor(m => m).Must(model => !CheckDuplicateDisplayName(model.DisplayName, model.Id)) .WithMessage(localizer["User.Fields.DisplayName.Unique"]) .OverridePropertyName(nameof(UserModel.DisplayName)); }); RuleFor(m => m.UserName).NotEmpty() .WithMessage(localizer["User.Fields.UserName.Required"]) .MinimumLength(3) .WithMessage(localizer["User.Fields.UserName.MinimumLength"]) .MaximumLength(User.MaxUserNameLength) .WithMessage(localizer["User.Fields.UserName.MaximumLength"]) .Matches("^[a-zA-Z0-9_]*$") .WithMessage(localizer["User.Fields.UserName.RegularExpression"]) .DependentRules(() => { RuleFor(m => m).Must(model => !CheckDuplicateUserName(model.UserName, model.Id)) .WithMessage(localizer["User.Fields.UserName.Unique"]) .OverridePropertyName(nameof(UserModel.UserName)); }); RuleFor(m => m.Password).NotEmpty() .WithMessage(localizer["User.Fields.Password.Required"]) .When(m => m.IsNew, ApplyConditionTo.CurrentValidator) .MinimumLength(6) .WithMessage(localizer["User.Fields.Password.MinimumLength"]) .MaximumLength(User.MaxPasswordLength) .WithMessage(localizer["User.Fields.Password.MaximumLength"]); RuleFor(m => m).Must(model => !CheckDuplicateRoles(model)) .WithMessage(localizer["User.Fields.Roles.Unique"]) .When(m => m.Roles != null && m.Roles.Any(r => !r.IsDeleted)); } private bool CheckDuplicateUserName(string userName, long id) { var normalizedUserName = userName.ToUpperInvariant(); return _uow.Set<User>().Any(u => u.NormalizedUserName == normalizedUserName && u.Id != id); } private bool CheckDuplicateDisplayName(string displayName, long id) { var normalizedDisplayName = displayName.NormalizePersianTitle(); return _uow.Set<User>().Any(u => u.NormalizedDisplayName == normalizedDisplayName && u.Id != id); } private bool CheckDuplicateRoles(UserModel model) { var roles = model.Roles.Where(a => !a.IsDeleted); return roles.GroupBy(r => r.RoleId).Any(r => r.Count() > 1); } }
به عنوان مثال در این اعتبارسنج بالا، قواعدی از جمله بررسی تکراری بودن نامکاربری و از این دست اعتبارسنجیها نیز انجام شده است. نکته حائز اهمیت آن متد CheckDuplicateRoles میباشد:
private bool CheckDuplicateRoles(UserModel model) { var roles = model.Roles.Where(a => !a.IsDeleted); return roles.GroupBy(r => r.RoleId).Any(r => r.Count() > 1); }
با توجه به «نکته مهم» ابتدای بحث، model.Roles، شامل تمام گروههای کاربری متصل شده به کاربر میباشند که در این لیست برخی از آنها با TrackingState.Deleted، برخی دیگر با TrackingState.Added و ... علامتگذاری شدهاند. لذا برای بررسی یکتایی و عدم تکرار در این سناریوها نیاز به اجری پرسوجویی بر روی دیتابیس نمیباشد. بدین منظور، با اعمال یک شرط، گروههای حذف شده را از بررسی خارج کردهایم؛ چرا که آنها بعد از عبور از منطق تجاری، حذف خواهند شد.
گام سوم: پیادهسازی سرویس متناظر
public interface IUserService : ICrudService<long, UserReadModel, UserModel> { }
public class UserService : CrudService<User, long, UserReadModel, UserModel>, IUserService { private readonly IUserManager _manager; public UserService(CrudServiceDependency dependency, IUserManager manager) : base(dependency) { _manager = manager ?? throw new ArgumentNullException(nameof(manager)); } protected override IQueryable<User> BuildFindQuery() { return base.BuildFindQuery() .Include(u => u.Roles) .Include(u => u.Permissions); } protected override IQueryable<UserReadModel> BuildReadQuery(FilteredPagedQueryModel model) { return EntitySet.AsNoTracking().Select(u => new UserReadModel { Id = u.Id, RowVersion = u.RowVersion, IsActive = u.IsActive, UserName = u.UserName, DisplayName = u.DisplayName, LastLoggedInDateTime = u.LastLoggedInDateTime }); } protected override User MapToEntity(UserModel model) { return new User { Id = model.Id, RowVersion = model.RowVersion, IsActive = model.IsActive, DisplayName = model.DisplayName, UserName = model.UserName, NormalizedUserName = model.UserName.ToUpperInvariant(), NormalizedDisplayName = model.DisplayName.NormalizePersianTitle(), Roles = model.Roles.Select(r => new UserRole {Id = r.Id, RoleId = r.RoleId, TrackingState = r.TrackingState}).ToList(), Permissions = model.Permissions.Select(p => new UserPermission { Id = p.Id, TrackingState = p.TrackingState, IsGranted = true, Name = p.Name }).Union(model.IgnoredPermissions.Select(p => new UserPermission { Id = p.Id, TrackingState = p.TrackingState, IsGranted = false, Name = p.Name })).ToList() }; } protected override UserModel MapToModel(User entity) { return new UserModel { Id = entity.Id, RowVersion = entity.RowVersion, IsActive = entity.IsActive, DisplayName = entity.DisplayName, UserName = entity.UserName, Roles = entity.Roles.Select(r => new UserRoleModel {Id = r.Id, RoleId = r.RoleId, TrackingState = r.TrackingState}).ToList(), Permissions = entity.Permissions.Where(p => p.IsGranted).Select(p => new PermissionModel { Id = p.Id, TrackingState = p.TrackingState, Name = p.Name }).ToList(), IgnoredPermissions = entity.Permissions.Where(p => !p.IsGranted).Select(p => new PermissionModel { Id = p.Id, TrackingState = p.TrackingState, Name = p.Name }).ToList() }; } protected override Task BeforeSaveAsync(IReadOnlyList<User> entities, List<UserModel> models) { ApplyPasswordHash(entities, models); ApplySerialNumber(entities, models); return base.BeforeSaveAsync(entities, models); } private void ApplySerialNumber(IEnumerable<User> entities, IReadOnlyList<UserModel> models) { var i = 0; foreach (var entity in entities) { var model = models[i++]; if (model.IsNew || !model.IsActive || !model.Password.IsEmpty() || model.Roles.Any(a => a.IsNew || a.IsDeleted) || model.IgnoredPermissions.Any(p => p.IsDeleted || p.IsNew) || model.Permissions.Any(p => p.IsDeleted || p.IsNew)) { entity.SerialNumber = _manager.NewSerialNumber(); } else { //prevent include SerialNumber in update query UnitOfWork.Entry(entity).Property(a => a.SerialNumber).IsModified = false; } } } private void ApplyPasswordHash(IEnumerable<User> entities, IReadOnlyList<UserModel> models) { var i = 0; foreach (var entity in entities) { var model = models[i++]; if (model.IsNew || !model.Password.IsEmpty()) { entity.PasswordHash = _manager.HashPassword(model.Password); } else { //prevent include PasswordHash in update query UnitOfWork.Entry(entity).Property(a => a.PasswordHash).IsModified = false; } } } }
در سناریوهای Master-Detail نیاز است متد دیگری تحت عنوان BuildFindQuery را نیز بازنویسی کنید. این متد برای بقیه حالات نیاز به بازنویسی نداشت؛ چرا که یک تک موجودیت واکشی میشد و خبری از موجودیتهای Detail نبود. در اینجا لازم است تا روش تولید کوئری FindAsyn رو بازنویسی کنیم تا جزئیات دیگری را نیز واکشی کنیم. به عنوان مثال در اینجا Roles و Permissions کاربر نیز Include شدهاند.
نکته: بازنویسی BuildFindQuery را شاید بتوان با روشهای دیگری هم مانند تزئین موجودیتهای وابسته با یک DetailOfAttribute و مشخص کردن نوع موجودیت اصلی، نیز جایگزین کرد.
متدهای MapToModel و MapToEntity هم به مانند قبل پیادهسازی شدهاند. موضوع دیگری که در برخی از سناریوها پیش خواهد آمد، مربوط است به خصوصیتی که در زمان ثبت ضروری میباشد، ولی در زمان ویرایش اگر مقدار داشت باید با اطلاعات موجود در دیتابیس جایگزین شود؛ مانند Password و SerialNumber در موجودیت کاربر. برای این حالت میتوان از متد BeforeSaveAsync بهره برد؛ به عنوان مثال برای SerialNumber:
private void ApplySerialNumber(IEnumerable<User> entities, IReadOnlyList<UserModel> models) { var i = 0; foreach (var entity in entities) { var model = models[i++]; if (model.IsNew || !model.IsActive || !model.Password.IsEmpty() || model.Roles.Any(a => a.IsNew || a.IsDeleted) || model.IgnoredPermissions.Any(p => p.IsDeleted || p.IsNew) || model.Permissions.Any(p => p.IsDeleted || p.IsNew)) { entity.SerialNumber = _manager.NewSerialNumber(); } else { //prevent include SerialNumber in update query UnitOfWork.Entry(entity).Property(a => a.SerialNumber).IsModified = false; } } }
در اینجا ابتدا بررسی شدهاست که اگر کاربر، جدید میباشد، غیرفعال شده است، کلمه عبور او تغییر داده شده است و یا تغییراتی در دسترسیها و گروههای کاربری او وجود دارد، یک SerialNumber جدید ایجاد کند. در غیر این صورت با توجه به اینکه برای عملیات ویرایش، به صورت منفصل عمل میکنیم، نیاز است تا به شکل بالا، از قید این فیلد در کوئری ویرایش، جلوگیری کنیم.
نکته: متد BeforeSaveAsync دقیقا بعد از ردیابی شدن وهلههای موجودیت توسط Context برنامه و دقیقا قبل از UnitOfWork.SaveChange فراخوانی خواهد شد.
if (Membership.ValidateUser(UserName, Password)) { FormsAuthentication.RedirectFromLoginPage(UserName, true); return true; }
<authentication mode="Forms" > <forms loginUrl="~/Account/Login" protection="All" timeout="30" name="myAppCookie" path="/" requireSSL="false" slidingExpiration="true" cookieless="UseCookies" enableCrossAppRedirects="false" /> </authentication> <membership > <providers> <clear /> <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="myApp " /> </providers> </membership> <profile> <providers> <clear /> <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="myApp " /> </providers> </profile> <roleManager enabled="true"> <providers> <clear /> <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="myApp "/> <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="myApp " /> </providers> </roleManager>
Relying party application
هر برنامه سمت client که از Claim پشتیبانی کند
مزایای Claim
عناصر Claim
Claim شامل عناصر زیر میباشد :
قبلا در همین وبسایت در مورد یکسانسازی حروف "ی" و "ک" مطلبی بیان شده است. تمرکز آن مطلب بر روی اعمال تغییرات، قبل از ذخیره در دیتابیس با استفاده از EF است. به عبارتی، متنهایی که توسط مدیر سایت یا هر کاربر دیگری برای ذخیره شدن در دیتابیس وارد شده است. اما در صورتی که کاربری در جستجوی خود از حروف "ی" و "ک" عربی استفاده کند چه میشود؟ در اینجا میخواهیم روشی را پیادهسازی کنیم که عمومی بوده و بتواند هر دوی این حالات را پوشش دهد.
مسئله این است که بایستی تمام ورودیهای کاربران سایت که از نوع رشته هستند چک و در صورت نیاز اصلاح شوند. بهترین روشی که به ذهن من میرسد این است که در فرایند Model Binding این عمل انجام بگیرد. با تعریف یک Model Binder برای نوع رشته میتوانیم عمل یکدستسازی را به صورت عمومی در تمام وبسایت اعمال کنیم.
در MVC یک Model Binder پیشفرض داریم به نام DefaultModelBinder . ما هم از همین کلاس استفاده میکنیم تا تمام کارها را برای ما انجام دهد. تنها بایستی در متد BindModel آن کد موردنظر خود را اضافه کنیم و سپس اجازه دهیم بقیه فرایند به شکل عادی ادامه پیدا کند.
کلاسی به نام StringModelBinder اضافه کرده و کلاس DefaultModelBinder را به عنوان کلاس پایه آن تعریف میکنیم. سپس متد BindModel آنرا override کرده، کد مربوط به یکدستسازی را اضافه میکنیم :
public class StringModelBinder : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { object value = base.BindModel(controllerContext, bindingContext); if (value == null) { return value; } return value.ToString().Replace((char)1610, (char)1740).Replace((char)1603, (char)1705); } }
ابتدا مقدار به دست آمده توسط متد پیشفرض را میگیریم. سپس در صورت نیاز یکسانسازی را انجام میدهیم.
برای فعال کردن این Model Binder بایستی آنرا در رویداد Application_start برنامه، برای نوع رشته به ModelBinderهای برنامه اضافه کنیم :
ModelBinders.Binders.Add(typeof(string), new StringModelBinder());
public boolean isNetworkAvailable(Context context) { ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); return activeNetworkInfo != null && activeNetworkInfo.isConnected(); }
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
public boolean IsInternetConnected() { try { Process ipProcess = Runtime.getRuntime().exec("/system/bin/ping -c 1 4.2.2.4"); int exitValue = ipProcess.waitFor(); return (exitValue == 0); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } return false; }
System.Diagnostics.Process.Start("processName");
public Process exec(String prog) throws java.io.IOException { return exec(prog, null, null); }
public abstract int waitFor() throws InterruptedException;
<uses-permission android:name="android.permission.INTERNET"/>
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); try { InputStream in = new BufferedInputStream(urlConnection.getInputStream()); if (!url.getHost().equals(urlConnection.getURL().getHost())) { // we were redirected! Kick the user out to the browser to sign on? ... } finally { urlConnection.disconnect(); } }