Наш разговор немного уходит от основной темы, здесь ведь можно обмениваться контактами? Я могу что-нибудь отправить вам на почту, если узнаю её. А моя почта - globus81yandex.ru
Я и ответил: Unity3D, как правильно подсказывают, для 2D в том числе.
Но если мсье не устраивают данные ответы, то ещё Monodevelop, Monogame приходят в голову.
Кстати, момент интересный, я как-то всё хотел упомянуть его в своём ответе, да забыл.
Постараюсь немножко подытожить. Большая часть моего ответа посвящена именно N-Layer архитектуре, т.е. разбиению вашего приложения на логические слои. Это помогает инвертировать зависимости и сделать приложение зависимым не от конкретной реализации, а от интерфейсов, что позволяет, к примеру, подменять базу данных или ORM без изменения клиентской части. Но вы это и сами всё прекрасно понимаете.
Разумеется такой подход не даёт роста производительности.
Сразу скажу, что я никогда не делал распределённых вэб-приложений, но по самой первой ссылке, которую я привёл, Александр как-раз и описывает данную тему. Т.е. по сути там ведётся речь как раз об N-Tier архитектуре.
Ок, Я сегодня чуть попозже найду статьи, заодним ссылку гляну. В InitializeSimpleMembership не делается ничего сверхъественного, там просто как-раз-таки и находится код подключения провайдера к базе. При каждом запросе к контроллеру аттрибут проверяет был ли инициализирован провайдер, и если нет, то он его инициализирует. На самом деле это не единственный вариант, я вам дам ссылку где можно сделать по-другому. Причём сам я тоже так делаю - вы просто в Global.asax прописываете эту строку инициализации и всё. В общем попозже я в комментариях дам ссылки.
Не могу найти ссылку сейчас, к сожалению, там обсуждались минусы данной технологии. А вы просто попробуйте хотя бы SimpleMembership (С Identity я сам пока не разбирался), уроков по нему достаточно, он достаточно гибкий и лаконичный. В нём, вместе порядка 10 (или сколько там в ASP.NET Membership) задаётся все 4 с минимальным количеством полей. Это во-первых. Во-вторых, таблица с именами пользователей и идентификаторами может быть интегрирована в любую таблицу вашей БД.
Т.е. насколько я помню в ASP.NET Membership таблица с именами пользователей достаточно большая, в ней много полей. СОответственно когда вы создаёте дополнительную информацию по пользователям (например имя и фамилию) вы либо добавляете эти поля в эту же таблицу и она становится ещё больше и уродливее (различные служебные поля ASP.NET Membership с хитрыми названиями смешиваются с вашими данными), либо создаёте связь один-к-одному и тогда многие ваши запросы начинают строиться на JOIN-ах, что ведёт к меньшей производительности (насколько я это всё знаю).
В случае с SimpleMembership вы всего лишь в паре строк кода указываете к какой таблице вы хотите присоединить данный провайдер и как называются поля с ID и UserName. Т.е. ваша таблица пользователей должна обязательно содержать два подобных поля, причём названы они могут быть как угодно. И всё. Вы инициализируете провайдер, указав на эту таблицу. Остальные небольшие таблицы он создаёт сам.
Конечно данный подход удобного использовать совместно с Code-First EF. Но в принципе не вижу прошлем использования и с другими технологиями. Попробуйте и вы сразу поймёте, что этот провайдер гораздо лаконичнее. В 12 студии с MVC4 он точно настроен по-умолчанию, насчёт 10-ой что-то не припоминаю. Если надо - дам ссылки как разобраться, там всё понятно за 10 минут изучения становится.
К тому же сессия, насколько я помню, уникальна в рамках каждого сервера. Т.е. если несколько серверов обрабатывает вашу логику, то изначально сессия будет сохранена только на одном и нужно будет решать проблему синхронизации информации между ними, насколько я знаю.
Да вполне нормальный стиль.
Из названия ProductListViewModel предельно ясно, что это ViewModel для действия List.
По теме: "получается что для каждого представления своя модель, не смотря на копипаст полей из сущностей домена" - да, всё верно. Для каждой View вы используете специальную ViewModel, даже тогда, когда она полностью копирует свойства доменного объекта.
Часто методы Create и Edit действительно имеют одинаковую модель. Здесь можно поступить несколькими способами:
1. Сделать так, как вам ответили выше
2. В методе Create использовать ProductEditViewModel. В этом случае ID у вас будет просто 0, всё-равно он нигде не используется. Модель может называться, к примеру CreateEditViewModel
3. Использовать раздельные модели.
Лично я предпочитаю третий вариант. Конечно он ведёт к некому дублированию кода, но я бы назвал это дублированием с натяжкой. Во-первых, вы не копируете никакого поведения, только свойства. Во-вторых этот способ всё-таки избавляет от наследования (я уже дискутировал на тему того, что не стоит использовать наследование только потому, что можно это делать, особенно если речь идёт про пару свойств). В-третьих такое решение гораздо гибче. Как только ваше действия Create и Edit начнут использовать разные свойства моделей, вам, возможно, придётся убирать наследование и всё-таки писать отдельные свойства.
По-поводу второго вопроса - на мой взгляд модель сформирована верно. Ваши продукты сгруппированы по разделам. В цикле вы пробегаете по разделам, где далее пробегаете по продуктам. По-моему, всё правильно.
Согласен с самокрутом - как вы сами хотите выбирать объект и выполнять его методы?
Если метод класса, перебирающий ваш список, проверяет объекты на типы и вызывает какие-то соответствующие действия, то вероятно есть проблема в архитектуре, т.к. вы переходите от ООП к процедурному программированию.
Я понимаю, что приведение типов вас не устраивает, но, На мой взгляд, здесь не применимы какие-либо паттерны. Ещё раз, Как сказал самокрут - как вы будете решать проблему выбора? У вас есть три объекта с разными методами. Ваш класс перебирает список, определяет тип объекта и вызывает соответствующий метод. Это немного не провославный ООП.
Вместо этого создаёте интерфейс (ну или класс) и используете наследование. Далее, в зависимости от задачи, можно применить, например, паттерн посетитель. Просто надо смотреть что вы хотите, без примера сложно понять.
Копайте в сторону правильной архитектуры.
@MIsternik Entity Framework используете? Если да, то name должен быть такой же, как название вашего DbContext (если используете Code First), в противном случае вам нужно явно указать строку подключения для контекста.
В остальном вроде всё так (хотя я не большой специалист, никогда не разворачивал сервер сам). Но в теории вы устанавливаете на серверный компьютер SqlServer. При этом адрес сервера для подключения будет называться: .\SQLEXPRESS (просто часто в этом путаются,). Повторюсь, я не большой спец в sql серверах, может быть у вас настроено какое-то другое имя. В любом случае если вы через Sql Server Management можете подключиться к своей базе, то оттуда имя сервера и берите).
Initial Catalog - название самой базы, да.
Про провайдера уже написал. Насчёт имени и пароля, тогда нужно добавить несколько параметров:
User ID=myUsername;Password=myPassword;
Тогда строка будет примерно такой:
< add name="MyDatabase" connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=MyDatabase;Persist Security Info=True;User ID=Entity;Password=SomePassword" providerName="System.Data.SqlClient" / >
Сложно сказать однозначно, нужно спросить тех, кто занимается в геймдевом (у меня, к сожалению, опыт в этом деле не очень большой пока).
Но моё мнение, что конечно используют :) TDD помогает построить ясную архитектуру, поэтому он может быть полезен в проектировании каркаса приложения, а также для тестирования отдельных модулей (например для тестирования уменьшение здоровья персонажа при попадании и т.д.), что в дальнейшем позволит вам контролировать целостность кода. Т.е. когда начинаешь применять тестирование - на любом этапе видишь, что после внесения изменений предыдущий код всё ещё работает - это очень удобно.
Другое дело, что игровые приложения зачастую очень тесно завязаны на различные библиотеки работы с графикой, что, на мой взгляд, несколько затрудняет тестирование.
Также игры тесно завязаны на ресурсы, на текстуры, на звуки и т.д. Поэтому чаще требуется визуальный контроль того, что получилось. Тесты в данном случае замедлят разработку, поэтому не вижу смысла тестировать здесь и всё и вся.
Если, для примера, взять игру в танки, то можно мыслить следующим образом:
1. Нам нужен некий игровой мир, который будет хранить информацию об игровых объектах, а так же отрисовывать их и обновлять.
Допустим у него будут методы Render и Update. Также будет приватное поле - список игровых объектов, которые есть в нашем мире. В таком случае методы Render и Update должны просто пробегать по этому списку и вызывать соответствующие методы Render и Update для каждого объекта в списке. В данном случае я не вижу никакой необходимости тестирования, т.к. код вообще максимально простой. (с другой стороны, если вы не уверены, что потом не испортите этот код, то уже сейчас можете написать тест, чтобы убедиться, что для всех элементов коллекции вызывается и Update и Draw).
2. Теперь вы хотите сделать имитацию попадания в танк. Здесь тест уже более оправдан. ПОэтому можете написать новый тест для несуществующего пока метода hit. Как я уже говорил, TDD помогает мыслить в ключе контракта, а не реализации. Во время написания теста вы будете думать не о том, как вам уменьшить здоровье танка, а о том, как написать красивый интерфейс для метода попадания в танк. Итак, вы пишете тест, в котором тестируете метод hit. Затем убеждаетесь, что тест не проходит, реализуете сам метод, проверяете, что теперь всё работает.
Польза в тестировании метода hit Заключается ещё и в том, что в дальнейшем его лоигка обязательно усложнится. Танки начнут получать повреждения в зависимости от типа снарядов и брони. Тесты помогут вам не запутаться и быть уверенным в том, что ваш метод работает как надо. Попробовал TDD вы сами потом поймёте, что без тестов нет вообще никакой гарантии, что код, который вы писали месяц назад, всё ещё работает.
3. После попадания в танк его нужно как-то убрать с карты. Раз уж за объекты нашего мира отвечает отдельный класс World (О котором я говорил в первом пункте), то за их удаление отвечать тоже должен он.
Вот здесь уже имеет смысл начать писать тест для метода Update. Наша логика такая: в методе Update наш мир пробегает по игровым объектам и смотрит их свойтво IsAlive. Если оно true, то обновляем наш объект. Если flase - убираем его с карты, и доверяем его судьбу сборщику мусора. Чувствуете, что логика усложнилась? В дальнейшем, возможно, она усложнится ещё больше, поэтому прямо сейчас, до реализации, напишем тест, в котором добавим в игровой мир несколько объектов - пару живых и один подбитый. Вызовем Update и удостоверимся, что два объекта были обновлены, а один удалён.
Вот такой вот принцип.
В общем мне кажется, что покрытие тестами игровых проектов бывает куда меньше, чем в прикладных. Если в двух словах, то мы тестируем логику работы отдельных методов объектов, но практически не тестируем то, что связано с графикой.
Не говоря уже о том, что огромная часть графического 3d приложения - это вообще шейдеры. Как их тестируют или тестируют ли вообще - я не знаю
Ещё я не вижу особого смысла тестировать всякие там вводы с клавиатуры и т.д. В общем нужно смотреть по ситуации.
Вот с этого и надо начать, уважаемый. Прямо сейчас открывайте ссылку vimeo.com/9541997 и смотрите видео.
Тот же урок в текстовом формате. blog.byndyu.ru/2010/01/tdd.html
Раньше я тоже ничего не тестировал, а теперь совершенно не понимаю как я мог так программировать.
Использование TDD как раз поможет мыслить вам в ключе построения правильной архитектуры, компоненты которой будут слабо связаны. Со временем вы перестанете в первую очередь думать о реализации компонентов и начнёте думать об их взаимосвязи. Начав писать первые тесты для компонентов вы сразу поймёте плюсы использования интерфейсов.
В общем смотрите урок - Александр там всё очень подробно и понятно объясняет.
Я тоже склоняюсь, что дело в SelectedRule. Вы отладчиком-то пользуетесь? F5 нажимаете и смотрите в каком месте вылетело исключение. Ну и находите какой из объектов у вас Null.
NullReferenceException - это и есть исключение, выпадающее, когда какой-либо объект не указывает на область в памяти. В данном случае вы нигде не инициализируете свой SelectedRule. Вы объявили поле в классе, но не проинициализировали его. не выделили память.