Страницы

Поиск по вопросам

Показаны сообщения с ярлыком asp.net-mvc. Показать все сообщения
Показаны сообщения с ярлыком asp.net-mvc. Показать все сообщения

понедельник, 13 апреля 2020 г.

Где лучше хранить двоичные данные: в БД или отдельном файле? [ASP.NET MVC 3]

#c_sharp #net #sql_server #aspnet_mvc

                    
Доброго времени суток.
Есть база данных в которой хранятся учётные записи пользователей. К каждому пользователю
привязаны два двоичных файла. Первый файл занимает около 30КБ, второй занимает около
300КБ. Со временем количество пользователей может исчисляться сотнями тысяч.
Первый вариант - хранить эти данные в базе данных. Поле Data в таблице будет иметь
тип varbinary(MAX):
public ActionResult GetWorld()
{
    var world = db.GetWorld(...);

    return File(world.Data, "application/octet-stream");
}

public ActionResult SaveWorld(HttpPostedFileBase worldData)
{
    var world = db.GetWorld(...);

    world.Data = new byte[worldData.ContentLength];
    worldData.InputStream.Read(world.Data, 0, worldData.ContentLength);
}

Второй вариант - хранить эти данные в виде отдельных файлов:
public ActionResult GetWorld()
{
    var world = db.GetWorld(...);

    string pathToWorldData = Server.MapPath(
        string.Format("~/App_Data/Worlds/{0}.dat", world.Id));

    return File(pathToWorldData, "application/octet-stream");
}

public ActionResult SaveWorld(HttpPostedFileBase worldData)
{
    var world = db.GetWorld(...);

    string pathToWorldData = Server.MapPath(
        string.Format("~/App_Data/Worlds/{0}.dat", world.Id));

    worldData.SaveAs(pathToWorldData);
}

Есть ещё другой вариант - varbinary(MAX) и FILESTREAM, но чем он по сути отличается
от второго? Только будет много возни в коде.    


Ответы

Ответ 1



Если хранить данные как поле таблицы, база будет пухнуть. Использование опции FILESTREAM позволяет хранить данные как отдельные файлы, но при этом с поддержкой транзакционности. Правда, лог базы данных всё равно будет пухнуть, его надо будет чистить периодически. Теперь о проблемах. FILESTREAM работает только с Windows-аутентификацией при обращении к БД. Возможно, я чего-то не нашёл, но по-другому у меня не получилось. В сочетании с тем, что диспетчер служб Windows любит терять пароли после пары перезагрузок, работать с этой опцией становится совсем весело. Ещё у меня была такая фигня, что после установки какого-то из обновлений Windows её было не включить. С учётом того, что Microsoft любят добавлять всё время новые возможности своих продуктов, не доводя до ума старые, используйте лучше файлы. Если так надо сделать поддержку транзакционности, посмотрите в сторону распределённых транзакций.

Ответ 2



Бинарные данные лучше хранить в файлах. Картинки, видео и музыку никто не хранит в БД. Не стоит лишний раз все усложнять. Для хранения большого количества файлов обычно создают множество подпапок, например можно хранить файлы для первой тысячи записей в папке /0/, для второй в /1/ и т. д.

Ответ 3



ну если есть деньги, то в БД, т.к. 500 мегабайт стандартно вроде, дальше уже доп $$$ а также из базы дольше дергаться будет, факт поле надо выбирать не varchar точно, раз ты байты будешь там хранить, лучше уж varbinary (кстати, для xml файлов есть тип xml в 2008) я бы посоветовал только путь к файлам хранить в БД, а файл дергать из файловой системы

Не получается создать базу данных

#c_sharp #aspnet_mvc #visual_studio

                    
Добрый день.
Проблема описана ниже.
 Выдержка из учебника:
 "... база данных добавляется в проект, и мы можем увидеть ее в папке App_Data. Теперь
в обозревателе баз данных (окно Database Explorer) мы можем подключиться к ней и создать
таблицы, которые будут хранить данные.
 Раскроем узел Creditbook.mdf и найдем узел Tables. Нажмем на этот узел правой кнопкой
мыши и в появившемся меню выберем пункт Add New Table."
У меня нет пункта Add New Table, есть только Обновить и Свойства. (У меня стоят SQL
Server и Management Studio). 
 Вот тут (http://www.sql.ru/forum/1038127/redaktirovanie-bd-v-s), у человека была
такая же проблема, но я всё равно не понял, что нужно делать. 
 Заранее спасибо за помощь.    


Ответы

Ответ 1



Нужно установить SQL Server Data Tools Проверял на Visual Studio 2015.

Ответ 2



Либо зайдите под админом в студию, либо поставьте себе SqlManagementStudio.

Ответ 3



Базу после создания таблицы нужно обновить, тогда вновь созданная таблица станет доступна (кнопка обновления прямо над ID).Обозреватель баз данных после данных действий также обновить желательно (кнопка левый верхний угол). В остальном все правильно работает.

Ответ 4



Для меня решение было таким: в VS жмем Tools->Extensions and Updates, выбрал обновление для VS, дальше надо поставить галочки, подождать пока установится и все заработает. По крайней мере у меня заработало.

суббота, 11 апреля 2020 г.

Ошибка при передачи данных из Html.DropDownListFor

#html #c_sharp #aspnet_mvc #razor

                    
Мне необходимо отобразить из БД в раскрывающий список ФИО, у которых столбец SubjectCode
равен 1.

Ege15VM.cs

namespace WebApplication1.Models
{
    public class Ege15VM
    {
        public IEnumerable Participants { get; set; }
        public string Participant { get; set; }

        public Ege15VM()
        {
            cokoEntitiesWAN dataContext = new cokoEntitiesWAN();
            Participants = from a in dataContext.ege_15_res_before
                           where a.SubjectCode == 1
                           select new SelectListItem
                           {
                              Text = a.surname + " " + a.name,
                              Value = a.ParticipantID,
                              Selected = false
                           };
        }
    }
}


Ege15.cshtml

@model WebApplication1.Models.Ege15VM

    @using (Html.BeginForm())
    {        
            Фамилия, Имя участника: @Html.DropDownListFor(x => x.Participant, Model.Participants)

        

} HomeController.cs [HttpGet] public ActionResult Ege15() { var model = new Ege15VM(); return View(model); } [HttpPost] public ActionResult Ege15(Ege15VM model) { return View(); } Представление нормально отображается и раскрывающий список содержит необходимые ФИО. Но если нажать на "Сформировать отчет", т.е. вызвать POST, выскакивает ошибка: Ссылка на объект не указывает на экземпляр объекта Сообщение ссылается на строку Фамилия, Имя участника: @Html.DropDownListFor(x => x.Participant, Model.Participants)


Ответы

Ответ 1



Вот эта строчка: return View(); возвращает View, который будет отрендерен на основе ModelData - данных, переданных от клиента. model при этом будет null. замените ее на return View(model);

четверг, 9 апреля 2020 г.

Подключение к базе данных. Когда создавать и сколько ему жить в веб-приложении?

#база_данных #aspnet #aspnet_mvc #http #веб_программирование

                    
Когда создавать подключение к базе данных?


На каждый запрос к базе
На каждый HTTP-запрос
Глобально в рамках домена - от старта приложения до его смерти


Первые два позволяют локализовать ошибки (обрыв связи с базой покрашит минимум запросов),
обеспечит многопоточную обработку запросов к базе(?) на стороне веб-сервера.

Третий - сократит оверхед на подключениях, особенно если БД вынесена на отдельный
сервер, но лишится плюсов первых двух.

Так что же лучше и в каких случаях стоит применять? Интересно это как по поводу чистого
ADO.NET, так и EF (если под "подключением" мы будем понимать наследника DbContext).
По поводу последнего в туториалах в интернете рассуждают о разнице между п.1 и п.2,
но не п.3. Почему?
    


Ответы

Ответ 1



Если у программиста возникает такой вопрос, то ему стоит использовать Entity Framework, по тому, что в данном случае фреймворк окажется умнее программиста, который своими попытками оптимизации с наибольшей вероятностью сделает только хуже. Во первых, DbContext, это Unit of Work(как и ISession в NHibernate) Наличие одного DbContext для всего приложения - плохая идея. Единственная ситуация, где это имеет смысл, когда у вас есть однопоточное приложение и база данных, которая используется исключительно этим экземпляром приложения. DbContext не поточно-безопасный, а так же DbContext кэширует данные, по этому вы быстро получите не актуальный кэш. Все это приведет к различным проблемам, когда несколько пользователей/приложений будут работать с этой базой данных одновременно. По этому если у вас не вышеописанная ситуация, то вам лучше инжектить DbContext в каждую задачу. Создавать же контекст на каждый запрос не лучший вариант с точки зрения производительности. Во первых при подключении происходит аутентификация и авторизация, во вторых вы теряете преимущества благодаря кешированию. Другими словами, вам нужно выделять DbContext на каждую бизнес-задачу.

вторник, 31 марта 2020 г.

Ошибка биндинга - приходит пустая модель

#c_sharp #aspnet_mvc


Есть два метода для редактирования 

Первый передает значения для редактирования, а второй редактирует

public ActionResult EditMagazine(int id)
{
    var editMagazineModel = new EditMagazineViewModel()
    {
        Magazine = magazineService.EditMagazine(id)
    };
    return View(editMagazineModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditMagazine1(EditMagazineViewModel magazine)
{
    var magazineModel = new Magazine
    {
        MagazineId = magazine.Magazine.MagazineId,
        Name = magazine.Magazine.Name,
        Number = magazine.Magazine.Number,
        YearOfPublishing = magazine.Magazine.YearOfPublishing
    };
    magazineService.EditMagazine1(magazineModel);
    return RedirectToAction("Magazine");
}


из-за того что делаю ViewModel пришлось столкнуться с mapping'ом ,

так вот проблема в том что во втором методе выходит исключение из-за этого 

var magazineModel = new Magazine
 {


я создаю новый обьект 

Кто подскажет как правильно передать значения с первого метода для второго метода 

[NullReferenceException: Object reference not set to an instance of an object.]


Вот ViewModel 

public class EditMagazineViewModel
{
    public Magazine Magazine { get; set; }       
}


а вот Model 

public class Magazine
{
    public int MagazineId { get; set; }
    public string Name { get; set; }
    public int Number { get; set; }
    public int YearOfPublishing { get; set; }
}


Вот View EditMagazine 

@model Library.ViewModel.MagazineViewModel.EditMagazineViewModel

@{
Layout = "~/Views/Home/Layout.cshtml";
}

 








 @using (Html.BeginForm("EditMagazine1", "Magazine"))

   {

       @Html.AntiForgeryToken()

    

Magazine


@Html.ValidationSummary(true, "", new { @class = "text-danger" }) @Html.HiddenFor(model => model.Magazine.MagazineId)
@Html.LabelFor(model => model.Magazine.Name, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.Magazine.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Magazine.Name, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.Magazine.Number, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.Magazine.Number, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Magazine.Number, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.Magazine.YearOfPublishing, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.Magazine.YearOfPublishing, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Magazine.YearOfPublishing, "", new { @class = "text-danger" })
}


Ответы

Ответ 1



Ваша модель основана на простых типах типа int и string: public class Magazine { public int MagazineId { get; set; } public string Name { get; set; } public int Number { get; set; } public int YearOfPublishing { get; set; } } При этом вы могли пойти по пути использования модели в качестве ViewModel - но раз уж вы пошли по пути ухода от модели - то не надо было во вьюмодели ссылаться на доменную логику: public class EditMagazineViewModel { public Magazine Magazine { get; set; } } Сделайте класс на простых типах: public class EditMagazineViewModel { public int MagazineId { get; set; } public string Name { get; set; } public int Number { get; set; } public int YearOfPublishing { get; set; } } (Чувствуете, что хочется записаться в сторонники использования моделей в качестве вьюмоделей? Код копипастится) Давайте теперь переделаем наш первый action: public ActionResult Edit(int id) { var magazine = magazineService.GetById(id); var model = new EditMagazineViewModel(magazine); return View(model); } и второй: [HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit(EditMagazineViewModel model) { if (!this.ModelState.IsValid) return this.View(model); var magazine = model.ToEntity(); magazineService.Update(magazine); return RedirectToAction("Magazine"); } (Обратите внимание: в сервис мы передаём уже доменную модель, сервис относится к слою бизнес-логики и может ничего не знать о десятках приложений (веб, мобильных) у каждого свои собственные вьюмодели) Только для этого нам нужно класс модели переписать следующим образом: public class EditMagazineViewModel { public EditMagazineViewModel() { } public EditMagazineViewModel(Magazine magazine) { this.MagazineId = magazine.MagazineId; this.Name = magazine.Name; this.Number = magazine.Number; this.YearOfPublishing = magazine.YearOfPublishing; } public Magazine ToEntity() { return new Magazine { MagazineId = this.MagazineId, Name = this.Name, Number = this.Number, YearOfPublishing = this.YearOfPublishing, }; } public int MagazineId { get; set; } public string Name { get; set; } public int Number { get; set; } public int YearOfPublishing { get; set; } } Первый конструктор нужен для asp.net, второй - для нас (чтобы не разбухал метод контроллера), а ToEntity - преобразует обратно ViewModel в Model. Понадобится - можете потом подтащить мапперы вместо этих методов. Остаётся переписать view: @model Library.ViewModel.MagazineViewModel.EditMagazineViewModel @{ Viewbag.Title = "Edit magazine"; }

@Viewbag.Title

@using (Html.BeginForm("EditMagazine", "Magazine", FormMethod.Post)) { @Html.AntiForgeryToken()
@Html.ValidationSummary(true, "", new { @class = "text-danger" }) @Html.HiddenFor(model => model.MagazineId)
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.Number, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.Number, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Number, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.YearOfPublishing, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.YearOfPublishing, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.YearOfPublishing, "", new { @class = "text-danger" })
} У меня в тестовом приложении работает (естественно чуть другие неймспейсы), проблем нет:

четверг, 19 марта 2020 г.

Как удалить записи из таблицы одной командой?

#aspnet #entity_framework #aspnet_mvc #sql


Не получается удалить записи в таблице! Нужно удалить все комментарии у которых item_id=6.
Этих комментарий штук 8. Пробую удалить таким образом:
IQueryable query = (from del in db.Comments where del.item_id == 6 select del);
db.DeleteObject(query);//ругается тут

Но пишет что:


Не удалось удалить объект, поскольку он не найден в ObjectStateManager.

однако, если я хочу удалить один комментарий, т.е. так:
Comment cquery = (from del in db.Comments where del.id == 4 select del).First();

то получается.
Как мне правильно написать, чтобы не применять foreach и подобные вещи, а удалить
сразу все комментарии, одним sql запросом (или командой, как правильнее сказать)?    


Ответы

Ответ 1



var query = from com in db.Comments where com.item_id == 6 select com; foreach (Comment comment in query) { // тут будет 1 запрос на выборку из бд db.Comments.Remove(comment); } db.SaveChanges(); // тут будет delete [dbo].[Comments] where ([Id] = 6) То есть удаление всех комментариев с item_id=6 произойдет с помощью одного SQL запроса

Ответ 2



А зачем foreach ? Можно же сделать так: context.YourTable.RemoveRange(context.YourTable); context.SaveChanges();

среда, 18 марта 2020 г.

Подключение скриптов в ASP.NET MVC

#javascript #aspnet_mvc


Здравствуйте. У меня такой вопрос. В ASP.NET MVC 4 скрипты можно подключать через
файл BundlesConfig.cs и потом на view рендерить их на странице такой инструкцией: 

@Scripts.Render("~/bundles/mybundle")


Напрашивается вопрос - а чем это лучше традиционного 




Во всяком случае при обычном способе нужно изменять только один файл, а не два как
в первом способе

Заранее спасибо
    


Ответы

Ответ 1



Бандлы подразумевают разделение подгружаемых скриптов на логические части. Допустим, отдельный бандл для стилей, отдельный бандл для JavaScript'овых библиотек, отдельный бандл для твоих скриптов. Править нужно только один файл, а не два. При компиляции страницы MVC сам вставит все необходимые теги.

пятница, 13 марта 2020 г.

Внедрение зависимостей в Owin

#aspnet_mvc #dependency_injection #aspnet_identity_2 #owin


В базовом шаблоне при создании asp.net mvc проекта в качестве системы авторизации
(по умолчанию) используется asp.net identity.

public class ApplicationUser : IdentityUser
{
    public async Task GenerateUserIdentityAsync(
        UserManager manager)
    {}
}

public class ApplicationUserManager : UserManager
{
    public ApplicationUserManager(IUserStore store)
        : base(store)
    {}

    public static ApplicationUserManager Create(
        IdentityFactoryOptions options,
        IOwinContext context)
    {}
}

public class ApplicationSignInManager : SignInManager
{
    public ApplicationSignInManager(
        ApplicationUserManager userManager,
        IAuthenticationManager authenticationManager) : 
        base(userManager, authenticationManager) { }

    public override Task CreateUserIdentityAsync(ApplicationUser user)
    {}

    public static ApplicationSignInManager Create(
        IdentityFactoryOptions options,
        IOwinContext context)
    {}
}

public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {}

    static ApplicationDbContext()
    {}

    public static ApplicationDbContext Create()
    {}
}


Указанные выше классы используются при настройки авторизации в приложении

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context, user manager and role manager to use
        // a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext(ApplicationUserManager.Create);
        app.CreatePerOwinContext(ApplicationRoleManager.Create);
        app.CreatePerOwinContext(ApplicationSignInManager.Create);

    }
}


Как в приведенном коде избавиться от сильной зависимости - app.CreatePerOwinContext()?
    


Ответы

Ответ 1



Воспользуемся IoC контейнером Autofac для внедрения зависимостей. При помощи менеджера пакетов Nuget установим необходимые пакеты: Autofac Autofac ASP.NET MVC 5 Integration Autofac OWIN Integration Внесем следующие изменения в класс Startup: private void ConfigureContainer(IAppBuilder app) { var builder = new ContainerBuilder(); // STANDARD MVC SETUP: // Register your MVC controllers. builder.RegisterControllers(typeof(MvcApplication).Assembly); // Run other optional steps, like registering model binders, // web abstractions, etc., then set the dependency resolver // to be Autofac. builder.RegisterType().As().InstancePerRequest(); builder.RegisterType() .As>().InstancePerRequest(); builder.RegisterType>() .As>().InstancePerRequest(); builder.Register((c, p) => c.Resolve() .Authentication).InstancePerRequest(); var dataProtectionProvider = app.GetDataProtectionProvider(); builder.Register>((c, p) => BuildUserManager(c, p, dataProtectionProvider)); var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); // OWIN MVC SETUP: // Register the Autofac middleware FIRST, then the Autofac MVC middleware. app.UseAutofacMiddleware(container); app.UseAutofacMvc(); } private UserManager BuildUserManager( IComponentContext context, IEnumerable parameters, IDataProtectionProvider dataProtectionProvider) { var manager = new ApplicationUserManager(context.Resolve>()); // Configure validation logic for usernames manager.UserValidator = new UserValidator(manager) { AllowOnlyAlphanumericUserNames = false, RequireUniqueEmail = true }; // Configure validation logic for passwords manager.PasswordValidator = new PasswordValidator { RequiredLength = 6, RequireNonLetterOrDigit = true, RequireDigit = true, RequireLowercase = true, RequireUppercase = true, }; // Configure user lockout defaults manager.UserLockoutEnabledByDefault = true; manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5); manager.MaxFailedAccessAttemptsBeforeLockout = 5; // Register two factor authentication providers. // This application uses Phone and Emails as a step of receiving a code // for verifying the user // You can write your own provider and plug it in here. manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider { MessageFormat = "Your security code is {0}" }); manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider { Subject = "Security Code", BodyFormat = "Your security code is {0}" }); //manager.EmailService = new EmailService(); //manager.SmsService = new SmsService(); if (dataProtectionProvider != null) { manager.UserTokenProvider = new DataProtectorTokenProvider( dataProtectionProvider.Create("ASP.NET Identity")); } return manager; } } Добавим вызов метода ConfigureContainer(IAppBuilder app) в метод Configuration(IAppBuilder app) public partial class Startup { public void Configuration(IAppBuilder app) { ConfigureAuth(app); ConfigureContainer(app); } } После выше приведенных действий можно удалить методы app.CreatePerOwinContext() из метода ConfigureAuth() так же необходимо модифицировать AccountControlle, ManageController: Убрать конструктор без параметров. Удалить следующие свойства: UserManager, SignInManager, AuthenticationManager Вот так может выглядеть AccountController после внесения необходимых изменений: public class AccountController : Controller { private readonly IAuthenticationManager _authenticationManager; private readonly SignInManager _signInManager; private readonly UserManager _userManager; public AccountController( UserManager userManager, SignInManager signInManager, IAuthenticationManager authenticationManager) { _authenticationManager = authenticationManager; _userManager = userManager; _signInManager = signInManager; } //Прочие необходимые методы } Использованные источники информации: Autofac’s documentation Habrahabr

Ответ 2



Строка app.CreatePerOwinContext(ApplicationUserManager.Create); нужна фреймворку для того чтобы можно было получть объект ApplicationUserManager в SecurityStampValidator. Не обязательно оставлять код для ApplicationUserManager.Create но нужно научить фреймворк как получать инстанс ApplicationUserManager. Если используется DI контейнер, то можно будет заменать на app.CreatePerOwinContext(() => DependencyResolver.Current.GetService());

воскресенье, 8 марта 2020 г.

Ninject не может создать обьект

#c_sharp #net #aspnet_mvc #inversion_of_control #ninject


При попытке создать обьект через контейнер Ninject вылетает exception : Object reference
not set to an instance of an object. Подскажите, пожалуйста, в чем может быть проблема?

Метод с класса NinjectDependencyResolver

private void AddBindings()
        {
            var mapperConfiguration = new MapperConfiguration(cfg =>
            {
                cfg.AddProfile(new TagProfile());
            });
            var mapper = mapperConfiguration.CreateMapper();
            _kernel.Bind().ToSelf().InRequestScope();
            _kernel.Bind, Repository>();
            _kernel.Bind().ToConstant(mapper);

            var repository = _kernel.Get>();// вылетает exception
            _kernel.Bind();
        }


Класс Repository

public class Repository : IRepository where T : class
{
    private readonly BlogDbContext _db;

    public Repository(BlogDbContext db)
    {
        _db = db;
    }
}


P.S. Не знаю важно ли это, но репозиторий с его интерфейсом находится в одной сборке,
а регистрация Ninject в другой.
    


Ответы

Ответ 1



Ошибка говорит о том, что в экземпляре объекта не задана ссылка на объект. Object reference not set to an instance of an object. В этих двух строчках _kernel.Bind, Repository>(); _kernel.Bind(); Вы "говорите" IoC-контейнеру, что при запросе IRepository или Repository, необходимо вернуть реализацию, но не указываете ее. Правильным будет следующий вызов. _kernel.Bind>().To>(); _kernel.Bind().To(); Вы сообщаете IoC-контейнеру, что при запросе IRepository создать экземпляр класса Repository. Для второй строки аналогично. И ответ на вопрос из комментария: для контекста делаю InRequestScope(), нужно ли мне это делать и для репозитория и для сервиса? Для репозитория и Сервиса не нужно делать InRequestScope(), только для контекста BlogDbContext UPD Не знаю важно ли это, но репозиторий с его интерфейсом находится в одной сборке, а регистрация Ninject в другой. Не важно, главное указать ссылка на сборку в которой лежит репозиторий и интерфейсы

Регулярное выражение для ФИО

#c_sharp #регулярные_выражения #aspnet_mvc


Нужно регулярное выражение где в имени первая буква должна быть большой и другие
большие буквы нужно запретить, за исключением случая когда имя пишется через дефис,
тогда разрешается большая буква первая и которая идет сразу после дефиса, остальные
нельзя. 
Например

Дмитрий - ОК

ДмИтрий - Ошибка

Дмитрий-Иосиф - ОК

ДмИтрий-Иосиф - Ошибка

Дмитрий-иосиф - Ошибка

Получилась регулярка у меня, только допускающая одну большую вначале, но через дефис
имя уже воспринимает неправильно т.к. после дефиса идет еще одна большая. 

Мое выражение

@"^[А-ЯЁ][а-яё\-]+\s([А-ЯЁ][а-яё\-]+)(\.|\s)\s*([А-ЯЁ][а-яё\-\.]+)$"

В нем используется шаблон Ф И О
    


Ответы

Ответ 1



Используйте ^\p{Lu}\p{Ll}*(?:-\p{Lu}\p{Ll}*)?$ См. демо регулярного выражения. Подробности: ^ - начало строки \p{Lu} - заглавная буква \p{Ll}* - 0 и более строчных букв (?:-\p{Lu}\p{Ll}*)? - необязательная последовательность следующих шаблонов: - - дефис \p{Lu} - заглавная буква \p{Ll}* - 0 и более строчных букв $ - конец строки. Если нужна поддержка только русских букв, замените \p{Lu} --> [А-ЯЁ] \p{Ll} --> [а-яё]

суббота, 7 марта 2020 г.

Можно ли в Visual Studio собирать проект на лету?

#visual_studio #aspnet_mvc #iis


При компиляции и запуске проекта ASP.NET MVC Core часть .cs файлов блокируется студией
и что б изменить код- надо "выключать сборку", изменять код, заново компилировать и
запускать изменённый проект, затрачивая время. 

Можно ли на лету после изменения .cs файла собрать проект и тут же увидеть в браузере
обновлённые данные, не перезапуская весь IIS ?
    


Ответы

Ответ 1



Можно, если использовать компьютер в качестве локального веб-сервера. Не путать с IIS Express, который открывает Visual Studio при запуске проекта. Следует заметить что компонент IIS включен как часть установки Windows как для сервера, так и для рабочих машин. Каждая версия OS Windows предлагает свою версию IIS: Windows 8 - IIS 8, Windows 7 - IIS 7/7.5 Чтобы установить его, необходимо выполнить следующие действия: Открыть панель управления Открыть "Программы" Открыть "Включение или отключение компонентов Windows". Выбрать Internet Information Services (Службы IIS) Убедитесь, что вы выбрали поддержку ASP.NET. Для этого раскройте узел Службы Интернета --> Компоненты разработки приложений --> ASP.NET (Internet Information Services --> World Wide Web Services --> Application Development Features --> ASP.NET) Если вы хотите использовать поддержку IIS в Visual Studio, которая позволяет вам создавать виртуальные каталоги IIS непосредственно в диалоговом окне New Web Site, вам нужно выбрать пункт «Совместимость управления IIS 6» в разделе «Средства управления веб-сайтом» (Web Management Tools --> IIS 6 Management Compatibility). Ok Убедитесь, что IIS активен: открыть localhost:80 в браузере. Ниже показана стандартная страница. Установить SQL Server и разрешить подключения Открыть Visual Studio с права администратора и создать виртуальный каталог для приложения: ПКМ по проекту --> Свойства --> Веб --> В разделе серверы выбрать "Локальный IIS" --> Нажать "Создать виртуальный каталог". Проект будет доступен по адресу указанному в графе URL-адрес проекта После написания кода собираем проект Ctrl+Shift+B и перезагружаем страницу в браузере. Для отладки Запускаем Visual Studio с правами администратора Жмем кнопку присоединиться (вверху на панельке, зеленая) Ставим галочку на "Показать процессы, запущенные всеми пользователями" Ищем процесс с названием "w3wp.exe" Жмем "Присоединиться"

пятница, 6 марта 2020 г.

Несколько вопросов по ASP.MVC и AJAX

#ajax #aspnet_mvc


Я только разбираюсь в ASP.MVC и может быть задаю глупые вопросы.
В данном случае вопросы будут не "как сделать", а "почему так происходит".
Делаю проект, суть которого заключается в том, что он обходит сайт, собирает ссылки
на его страницы и  измеряет время отклика. Потом, собранную информацию выводит в табличном
виде (пока).
Проект состоит из двух страниц. На первой - в соответствующем инпуте водится поле
и по нажатию кнопки идет переход на другой контроллер (ToolController), который  производит
замеры и выводит результаты.

Код метода первого контроллера (HomeController):

public ActionResult Submit(string Url)
{
    if (CheckUrl(Url))
    {
        ViewBag.Error = "";
        return RedirectToAction("Index", "Tool", new { Url });
    }
    else
    {
        ViewBag.Error = "Некорректный адрес!"; 
        return RedirectToAction("Index");
    }

}


Валидацию пока можно не смотреть, это буду отдельно разбираться.

Представление (фрагмент):

 @using (Html.BeginForm("Submit", "Home", FormMethod.Post))
{
    
@Html.Label("Введите адрес сайта в поле ввода и нажмите кнопку")
@Html.TextBox("Url") @ViewBag.Error
} Во ToolController есть поле private поле класса VMManager, методы которого реализуют бизнес-логику. В классе VMManager есть поле вью-модели (VM), потому что все дальнейшие действия будут крутиться вокруг один раз построенной VM (сохранение в БД - пока не реализовано). Представление выводит таблицу, состоящую из ссылок на страницы сайта (Ajax.ActionLink), по нажатию на которые должно подгружаться partialView с графическим представлением информации. До графического представления мне пока далеко, пока разобраться бы что в табличном происходит. Фрагмент контроллера (ToolController): private static VMManager manager = new VMManager(); public ToolController() { // manager = new VMManager(); } // GET: Tool public ActionResult Index(string url) { // manager = new VMManager(); manager.VM = (SiteVM)manager.GetVM(url); return View(manager.VM); } public ActionResult ShowPageResultInChart(string pattern) { if (pattern == "test") return null; Thread.Sleep(1000); return PartialView("ShowPageResultInChart"); } Фрагмент представления: @Html.Action("ShowPageResultInChart", new { pattern ="test" }) @foreach (var item in Model.PageResults) { @Ajax.ActionLink(item.PageAddress, "ShowPageResultInChart", new {pattern= item.PageAddress }, new AjaxOptions { UpdateTargetId = "ChartData", LoadingElementId = "LoadingIndicator" } ) @item.MinTime @item.AverageTime @item.MaxTime } В частичном представлении пока смотреть нечего: строчка "Сработал Ajax" Теперь вопросы: Если верить отладчику, то при первичной загрузке основной страницы запускается метод ShowPageResultInChart. Хотя он предполагался к запуску только при нажатии на Ajax.ActionLink. Почему, что я сделал не так? От этой беды я избавился условием в методе ShowPageResultInChart, но почему он срабатывает? Я правильно понимаю, что это противоречит смыслу Ajax? Разместить его ниже таблицы я не могу по условиям задания. Причем у меня сложилось впечатление, что запускается он как минимум 2 раза, но может я ошибаюсь. Судя по всему, у меня запускается несколько экземпляров второго контроллера. Это я понял по тому, что VM в процессе обнуляется и при нажатии на Ajax.ActionLink на входе метода ShowPageResultInChart VM = null. Такое впечатление, что первый экземпляр создается при выводе таблицы, второй - при нажатии на Ajax.ActionLink. От этой беды я избавился сделав поле менеджера статическим, но почему так происходит?


Ответы

Ответ 1



1) ShowPageResultInChart вы вызываете не только с помощью @Ajax.ActionLink, а также с помощью @Html.Action, отсюда он и выполняется при загрузке страницы. @Html.Action("ShowPageResultInChart", new { pattern ="test" }) 2) При каждом запросе создается отдельный экземпляр класса Controller через ControllerFactory. Обратите внимание, что Html.Action Html Helper создаст другой экземпляр контроллера. В общем, ControllerActivator.Create вызывается (для каждого запроса), чтобы создать контроллер (который создает новый контроллера или через DependencyResolver или через Activator, если не Resolver не был установлен): public IController Create(RequestContext requestContext, Type controllerType) { try { return (IController) (_resolverThunk().GetService(controllerType) ? ? Activator.CreateInstance(controllerType)); }

среда, 4 марта 2020 г.

Как отправить @Html.HiddenFor(m => item.Id) в контроллер?

#c_sharp #aspnet_mvc


  @if (item.UserId == User.Identity.GetUserId().AsInt())
                {
                using (Html.BeginForm("Delete", "Home", FormMethod.Post))
                    {
                    @Html.AntiForgeryToken()
                    @Html.HiddenFor(m => item.Id)
                    
                    }
                }


Вот сам вид в html view

    [HttpPost]
    [Authorize]
    public ActionResult Delete(int Id)
    {
        var session = NHibernateHelper.GetCurrentSession();
        try
        {
            using (var transaction = session.BeginTransaction())
            {

                DBNewsItem newItem = new DBNewsItem();
                newItem.Id = Id;
                session.Delete(newItem);
                transaction.Commit();
            }
        }
        finally
        {
            NHibernateHelper.CloseSession();
        }
        return RedirectToAction("Index", "Home");
    }


А вот контроллер, который должен принимать id. Почему ему ничего не приходит?
    


Ответы

Ответ 1



В случаях, если вы вызываете XXXFor не для свойства модели, а для какого-то стороннего объекта вы рендерите View через PartialFor или какой-то еще способ рендеринга сложного темплйта для поля. ... MVC выставляет ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix - в зависимости от имени переменной или от имени свойства в родительской модели. Делается это для того, чтобы поля для разных Partial Views получили гарантированно разные имена в HTML. Поэтому в HTML вы получаете не "id", а какой-нибудь "item_id". Для того, чтобы сбайндить на сервере этот "item_id" в параметр id нужно посмотреть, какой префикс используется, и вписать его на сервере в виде атрибута параметра контроллера: Для сложных типов достаточно вписать сам префикс (имя свойства байндер вытянет сам). Для простых - придется вписать полное имя параметра: public ActionResult Delete([Bind(Prefix = "item.id")] int Id) { ... } Или принимать "модель целиком" (достаточно бессмысленно в вашем слуае) - тогда байндер вытянет данные по имени параметра + имени свойства: public ActionResult Delete(SomeItem item) // забайндит item.Id { ... } Это же применимо и к случаю, когда "приходит вся модель", но с общим префиксом - Bind(Prefix = "item") точно так же срабатывает в случае, если в partial была, например, отрендерена форма редактирования для нескольких полей. Но именно в вашем случае - решение с @Html.Hidden("Id", item.Id) надежнее и проще.

Ответ 2



Переделал вьюшку под @Html.Hidden("Id", item.Id) Потом передал через пост в контроллер public ActionResult Delete(int id){...} На прямую, через имя, обращаюсь Item.Id

Ответ 3



Наверное в метод приходит вся модель, попробуйте принимать её в метод. Т.е. ваше определение метода, будет выглядеть следующим образом (если тип модели DBNewsItem) public ActionResult Delete(DBNewsItem model)

вторник, 25 февраля 2020 г.

Visual Studio 2015, ASP.NET 5, Локальный сервер IIS

#aspnet_mvc #iis #visual_studio_2015


Есть проект написанный на ASP.NET 5.
Требуется запуск из Visual Studio 2015 в режиме отладки, но чтоб была возможность
подключения к нему по внешнему статическому IP.
Я так понимаю нужно использовать локальный сервер IIS.
Но как это настроить ?
    


Ответы

Ответ 1



Запустить студию с правами администратора Открыть свойства веб проекта в студии Перейти на закладу Web Сменить значение в комбобоксе Servers с IIS Express на Local IIS Нажать Create Virtual Directory Приложение будет доступно по Project Url, с подстановкой IP или внешнего имени машины вместо localhost. Запустить отладку можно по F5, или прицепившись у уже запущенному w3wp.exe через Debug → Attach To Process. Или можно просто вручную создать Application в IIS Manager, зайти на сайт, и точно так же прицепится отладчиком студии.

понедельник, 24 февраля 2020 г.

Как удалить много записей из базы данных [закрыт]

#sql #sql_server #aspnet_mvc #azure


        
             
                
                    
                        
                            Закрыт. Этот вопрос необходимо уточнить или дополнить
подробностями. Ответы на него в данный момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Добавьте больше подробностей
и уточните проблему, отредактировав это сообщение.
                        
                        Закрыт 4 года назад.
                                                                                
           
                
        
Простое удаление работает очень долго (около 40 секунд из одной таблицы, в которой
примерно 1,5 миллиона записей), нужно сделать быстрее (нужно удалить все данные пользователя).
База MSSQL.
    


Ответы

Ответ 1



Если нужно удалить ВСЕ записи из некоторой таблицы, используйте TRUNCATE, предварительно удалив внешние ключи, которые ссылаются на таблицу. Это самый быстрый способ. Он, в частности, игнорирует триггеры. Если просто большое количество, то нужно удалять пачками. Оптимизировал я job, который удалял устаревшие данные, порядка ~100млн. строк в неделю. запускался на выходных. Опытным путём пришёл к выводу, что быстрее всего строки удаляется пачками по 100-500 штук. Создаём временную табличку с ID'ами записей которые будем удалять. Пишем туда 100-500 ID'ов. и вызываем: DELETE T2 FROM #Table T1 INNER LOOP JOIN Table T2 ON T1.ID = T2.ID Здесь нужен именно LOOP. Хотя сервер скорее всего и без хинтов догадается. Вместо ID таблицы Table, может быть любой уникальный ключ. В случае, если ключ кластерный, то в таблицу #Table желательно вставлять ID'ы пачек строк, которые записаны в Table "рядом". Если целиком пачку удалить не удалось, вызываем удаление по одной записи и логируем результаты.(ну я так делал:)) потом утром анализируем. UPD: по поводу быстрого поиска удаляемых записей. Стоит создать индекс по UserId и посмотреть станет лучше или нет. UPD: чуть-чуть про то, почему именно пачками. Удаление по одной записи - это N транзакций. Выполняется довольно медленно... Таким был job до того, как я начал его оптимизировать. Пытаться удалить одним DML оператором ~1млн строк тоже плохо. Т.к. сама транзакция становится очень большой и рискуем получить нехватку памяти. Да и выполняется это долго. В итоге задавая размер пачки, я к каждой таблице подобрал оптимальное число одновременно удаляемых записей. Начальник был доволен(с) :)

Тестирование и избавление от связности классов.

#c_sharp #aspnet #aspnet_mvc #юнит_тесты #тестирование


Добрый день! У меня есть приложение asp.net mvc. В нем я пытаюсь создавать архитектуру
"по уму" - с Dependency Injection, тестами и тд. В приложении есть классы-сервис, в
которых сосредоточена бизнес-логика. Мне необходимо покрыть эти сервисы тестами. Многие
сервисы используют класс настроек, экземпляры которых им передаются в конструкторах.
Например: 

public class AppSettings  
{
    public AppSettings()
    {
        SomeStr =  WebConfigurationManager.AppSettings["str"]).ToString();  
        // и еще несколько подобных  строк         
    }

    public string SomeStr { get;set; }
}


public class MyService 
{
    public MyService(AppSettings settings)
    {
        _settings = settings;
    }

    private readonly AppSettings _settings;
}


Проблема тут вот какая. В конструкторе класса AppSettings происходит инициализация
неких переменных, данные о которых получаются из файла web.config. В коде самого приложения
это работает, а вот если я пытаюсь тестировать класс MyService в отдельном тестовом
приложении, то возникает проблема: классу нужно передавать экземпляр AppSettings, но
при его создании  вываливается исключение из-за невозможности обратиться к web.config.
Кроме того сами классы я напрямую не создаю, этим занимается DI-библиотека. Как быть
в данном случае и как нормально протестировать MyService? К тому же мне кажется проблемой
то, что в конструкторе класса AppSettings происходит обращение к `web.config. Подскажите
пожалуйста как решить эту проблему? Заранее благодарю.
    


Ответы

Ответ 1



Если вы используете класс AppSettings как класс настроек и IoC-контейнер, то опишите интерфейс IAppSettings и протестируйте с помощью Mock объектов. Приведу пример. В классе MyService вы заменяете тип аргумента конструктора settings на IAppSetting. В IoC-контейнере регистрируете реализацию. Предположим, что вы используете Ninject, тогда kernel.Bind().To(). Тогда в методе тестирования вы можете настроить свой объект. Mock() mock = new Mock(); mock.Setup(m => m.Field1).Returns(value1); MyService service = new MyService(mock.Object); Здесь вы задаете, что при запрашивании Field1 должно вернуться значение value1. Внимание поле Field1 должно быть определено в интерфейсе IAppSetting Пример показан для Ninject

воскресенье, 16 февраля 2020 г.

Тестирование и избавление от связности классов.

#c_sharp #aspnet #aspnet_mvc #юнит_тесты #тестирование


Добрый день! У меня есть приложение asp.net mvc. В нем я пытаюсь создавать архитектуру
"по уму" - с Dependency Injection, тестами и тд. В приложении есть классы-сервис, в
которых сосредоточена бизнес-логика. Мне необходимо покрыть эти сервисы тестами. Многие
сервисы используют класс настроек, экземпляры которых им передаются в конструкторах.
Например: 

public class AppSettings  
{
    public AppSettings()
    {
        SomeStr =  WebConfigurationManager.AppSettings["str"]).ToString();  
        // и еще несколько подобных  строк         
    }

    public string SomeStr { get;set; }
}


public class MyService 
{
    public MyService(AppSettings settings)
    {
        _settings = settings;
    }

    private readonly AppSettings _settings;
}


Проблема тут вот какая. В конструкторе класса AppSettings происходит инициализация
неких переменных, данные о которых получаются из файла web.config. В коде самого приложения
это работает, а вот если я пытаюсь тестировать класс MyService в отдельном тестовом
приложении, то возникает проблема: классу нужно передавать экземпляр AppSettings, но
при его создании  вываливается исключение из-за невозможности обратиться к web.config.
Кроме того сами классы я напрямую не создаю, этим занимается DI-библиотека. Как быть
в данном случае и как нормально протестировать MyService? К тому же мне кажется проблемой
то, что в конструкторе класса AppSettings происходит обращение к `web.config. Подскажите
пожалуйста как решить эту проблему? Заранее благодарю.
    


Ответы

Ответ 1



Если вы используете класс AppSettings как класс настроек и IoC-контейнер, то опишите интерфейс IAppSettings и протестируйте с помощью Mock объектов. Приведу пример. В классе MyService вы заменяете тип аргумента конструктора settings на IAppSetting. В IoC-контейнере регистрируете реализацию. Предположим, что вы используете Ninject, тогда kernel.Bind().To(). Тогда в методе тестирования вы можете настроить свой объект. Mock() mock = new Mock(); mock.Setup(m => m.Field1).Returns(value1); MyService service = new MyService(mock.Object); Здесь вы задаете, что при запрашивании Field1 должно вернуться значение value1. Внимание поле Field1 должно быть определено в интерфейсе IAppSetting Пример показан для Ninject

пятница, 14 февраля 2020 г.

Смещение часового пояса ASP.NET MVC

#c_sharp #net #aspnet_mvc #datetime


У меня есть сайт и сервер.
Хочу, чтобы клиентам из разных часовых поясов показывалось разное время.
Всю конвертацию провожу на сервере:

от клиента - 

return new DateTimeOffset(dateTime, TimeZoneInfo.Local.BaseUtcOffset);


клиенту - 

return ((DateTimeOffset)dateTime).LocalDateTime;


При тесте выяснил, что ASP.NET не умеет сам определять часовой пояс клиента, и его
надо определять с помощью JS и передавать при помощи кукис:

new Date().getTimezoneOffset();//gets the timezone offset


Вот тут время для вопроса. Каким образом прокидывать смещение от сайта до самого
сервера? Я хочу реализовать что-то наподобие

Thread.CurrentThread.CurrentUICulture = CultureInfo.***;


, без всяких хелперов и обёрток. Но раз в интернете я нигде не нашёл такого способа,
значит люди реализовывают смещение времени по другому. 
Как правильно поступить, если я хочу делать конвертацию смещения именно на сервере
и желательно стандартными средствами .NET?

UPD: схема такая: пользователь -> ASP.NET MVC 4 -> .exe служба на .NET -> SQL Server
    


Ответы

Ответ 1



Стандартного механизма нет по двум причинам. Первая из них - местным временем в .NET называют именно системное местное время, а не какое-то еще. А потому TimeZoneInfo.Local возвращает одно и то же для всех потоков и не может быть переопределено. Вторая - браузер не передает свой часовой пояс через заголовки HTTP (в отличии от языка, который передается в заголовке Accept-Language). Так что без хелперов и оберток не обойтись.

Ответ 2



Мы храним объект с разницей во времени между клиентом и сервером в сессии. Вернее, разницу между клиентским временем и UTC. B мастер-странице, при отсутствии этого объекта в сессии, вставляем вызов ajax-а, который отправляет getTimezoneOffset на сервер - в специальный контроллер, который создает объект и кладет его в сессию. Клиент - браузер. Сервер - компьютер с ASP.NET веб-приложением. Дату/время в базе данных следует хранить как UTC.

четверг, 13 февраля 2020 г.

Отмена действия

#c_sharp #aspnet_mvc #ui


Доброго времени суток.
Есть задача: возможность отмены собственных действий на сайте/форуме, например удалил
сообщение/коммент(не смотря на предварительно подтверждёный вопрос подтверждения) и
пожалел о содеяном, тогда подобная функция отмены будет очень кстати.
На данном ресурсе есть возможность отмены голоса ЗА и/или ПРОТИВ, которая достаточно
полезна.
Собственно вопрос: как реализовывать подобный функционал? Когда выполнять запрос
удаления записи(или любой другой операции) из базы? Или просто помечать запись определённым
флагом "deleted"? 
Какой метод решения является самым оптимальным? Просто придумать какой-нибудь велосипедо-костыль
не составит труда, хотелось бы всё сделать правильно.
Буду рад словесному описанию алгоритмов или ссылок на чтиво касающегося данной темы.
Зарание благодарю.
UPD: ответ тов. @wind хорош, но хотелось бы узнать по данной теме по-больше    


Ответы

Ответ 1



Для реализации отмены каких-либо действий однозначно нужно их где-то хранить, чтобы иметь возможность откатиться к прежней версии или восстановить удаленное. И так как мы говорим о веб-разработке, то у нас как обычно встает два варианта: клиент и сервер. Но выдумывать хранение данной информации на клиенте в куках или прям на странице или хз где еще, как по мне, как раз описанный вами "велик" (еще и не "секьюрно"). Следовательно нужно хранить на сервере, а раз мы выбираем сервер, то почему бы не юзать ту же БД, в которой итак все хранится. Поэтому я считаю, что оптимально использовать именно схему "с флагами в БД". Судя по вопросу вы вкурсе, как ее реализовать, да это и вовсе не сложно. Единственное, что хочу еще добавить, так это версионность, которая, как пример, реализована при редактировании вопросов на данном форуме. То есть можно в БД не только помечать запись какую-либо, как удаленную, а реализовать некую структуру для хранения версий постов, комментариев и тд. Имея данную структуру в БД, можно отменить не только одно действие, а вернуться к любому предыдущему, но это уже во многом зависит от задачи, нужно ли оно вообще вам или достаточно всего лишь отмены удаления. К тому же, если рассматривать какую-либо соц. сеть, то при удалении например профайла юзера, насколько я знаю, опять же используется данная схема, ну и было бы странно, если удалив юзера, со всего портала пропала оставленная им информация, хотя иногда это требуется по ТЗ и тогда "каскады" в БД или ОРМ сама подчистит все связанные с сущностью данные.

Ответ 2



Хранить в сессии историю команд. Интерфейс команды должен иметь методы Undo и Redo.

Структура asp.net mvc приложения

#aspnet #aspnet_mvc #mvc


Здравствуйте. Недавно меня заинтересовало, как красиво преобразовывать данные для
передачи в вид и вообще, как грамотно делать приложения на asp.net mvc. Здесь мне ответили. 
Я честно говоря не слишком понимаю эти термины пока не увижу код воочию.
Если кто-то программирует использую такой подход, то выложите здесь примеры или киньте
в скайпе: umnick.jo. Буду рад любой помощи. Спасибо    


Ответы

Ответ 1



В проекте должны быть 2 независимых модели данных: доменная модель и "вью модель". Чтобы преобразовать сущности доменной модели в сущности вью модели (или наоборот) для дальнейшего отображения во вьюхах удобно использовать AutoMapper или любой другой аналог. Пример: Этап конфигурации: Mapper.CreateMap() .ForMember(m => m.IsContainUsers, a => a.MapFrom(p => p.Subjects.Count > 0)); Обычно обе модели во многом совпадают (одинаковые свойства) и в подобном случае конфигурация будет состоять из одной строки создания "мапа", либо как в примере у вью-модели есть дополнительное свойство IsContainUsers, которое и сконфигурировано. Этап преобразования: var domainWatchList = GetFromDatabase(); var viewWatchList = Mapper.Map(domainWatchList);