Andrey on .NET | Основы. Часть 6 (продолжение) – Изменяем заготовки

Основы. Часть 6 (продолжение) – Изменяем заготовки

Давайте рассмотрим простой пример и внесем изменения в несколько заготовок. В частности укажем другие пространства имен и сделаем генерируемый исходный код в стиле остальных C#-файлов проекта.

Создание копий для модификации

Изменим код в следующих заготовках:

  • Контроллера, использующего Репозиторий: MvcScaffolding.Controller ControllerWithRepository;
  • Представление Index: MvcScaffolding.RazorView Index
  • Реализации репозитория Entity Framework: T4Scaffolding.EFRepository Repository;
  • Контекст базы данных: T4Scaffolding.EFDbContext DbContext

Откроем консоль NuGet и введем следующие команды:

PM> Scaffold CustomTemplate MvcScaffolding.Controller ControllerWithRepository
Added custom template 'CodeTemplates\Scaffolders\MvcScaffolding.Controller\ControllerWithRepository.cs.t4'
PM> Scaffold CustomTemplate MvcScaffolding.RazorView Index
Added custom template 'CodeTemplates\Scaffolders\MvcScaffolding.RazorView\Index.cs.t4'
PM> Scaffold CustomTemplate T4Scaffolding.EFRepository Repository
Added custom template 'CodeTemplates\Scaffolders\T4Scaffolding.EFRepository\Repository.cs.t4'
PM> Scaffold CustomTemplate T4Scaffolding.EFDbContext DbContext
Added custom template 'CodeTemplates\Scaffolders\T4Scaffolding.EFDbContext\DbContext.cs.t4'

Как видно из сообщений, копии файлов сохранены в добавленной в проект папке CodeTemplates. Теперь именно эти версии заготовок будут использоваться для генерации исходного кода.

Заготовки изнутри

Давайте посмотрим что из себя представляют заготовки. Если открыть в Visual Studio 2010 содержимое добавленных в проект файлов, то можно увидеть примерно вот такой код (часть файла Repository.cs.t4):

<#@ template language="C#" HostSpecific="True"  inherits="DynamicTransform" #>
<#@ assembly name="System.Data.Entity" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="EnvDTE" #>
<#@ Output Extension="cs" #>
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Web;
<# foreach(var ns in new[] { Model.ModelTypeNamespace, Model.DbContextNamespace }.Where(x => !string.IsNullOrEmpty(x) && (x != Model.RepositoryNamespace)).Distinct()) { #>
using <#= ns #>;
<# } #>

namespace <#= Model.RepositoryNamespace #>
{ 
<# 
    var modelType = (CodeType)Model.ModelType; 
    var modelName = modelType.Name; 
    var modelNamePlural = Model.ModelTypePluralized; 
    var contextName = ((CodeType)Model.DbContextType).Name; 
    var primaryKeyProperty = modelType.VisibleMembers().OfType<CodeProperty>().Single(x => x.Name == Model.PrimaryKey);
    var isObjectContext = ((CodeType)Model.DbContextType).IsAssignableTo<System.Data.Objects.ObjectContext>();
#>
    public class <#= modelName #>Repository : I<#= modelName #>Repository
    {
        <#= contextName #> context = new <#= contextName #>();

        public IQueryable<<#= modelName #>> All
        {
            get { return context.<#= modelNamePlural #>; }
        }

        public IQueryable<<#= modelName #>> AllIncluding(params Expression<Func<<#= modelName #>, object>>[] includeProperties)
        {
            IQueryable<<#= modelName #>> query = context.<#= modelNamePlural #>;
            foreach (var includeProperty in includeProperties) {
                query = query.Include(includeProperty);
            }
            return query;
        }
    .........

Как можно заметить, код читается достаточно легко. Даже без изучения синтаксиса T4 легко понять что будет сгенерировано на основе данной заготовки. По сути, приведен обычный исходный код, который будет перенесен в создаваемый файл. Однако при этом его часть будет сгенерирована программно. Для этого используются инструкции на языке C#, которые заключены между ключевыми словами <# и #>.

Вносим изменения

Всех файлах приложенного к этой статье проекта были сделаны изменения, касающиеся стиля исходного кода. Так как это не влияет на работоспособность создаваемого веб-приложения, то не будем рассматривать их детально. Вместо этого отметим только принципиальные изменения. Они коснутся местоположения файлов и пространств имен классов, которые в них содержатся.

В процессе генерации исходные файлы контекста базы данных и реализации репозитория будут созданы в папке Models. Гораздо логичнее было бы разместить их в папках Models\DbContext и Models\Repositories соответственно. Но для этого необходимо разработать свою версию PowerShell кода, который отвечает за настройку генерации файлов.

Чтобы не усложнять сейчас задачу изучением PowerShell, поступим следующим образом:

  • изменим пространства имен в заготовках так, чтобы в исходном коде генерировались:
    • <projectName>.Models.DbContext для контекста базы данных;
    • <projectName>.Models.Repositories для реализаций репозитория;
  • после создания файлов с исходным кодом самостоятельно перенесем их в соответствующие папки.

Давайте непосредственно посмотрим на изменения:

Файл: MvcScaffolding.Controller\ControllerWithRepository.cs.t4

Из заготовки Контроллера удалим метод, реализующий Действие Details. Оно отвечает за вывод подробной информации и в данном проекте не потребуется. Кроме того, добавим поддержку пространства имён <projectName>.Models.Repositories.

<#@ template language="C#" HostSpecific="True"  inherits="DynamicTransform" #>
<#@ Output Extension="cs" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="EnvDTE" #>
namespace <#= Model.ControllerNamespace #>
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
<# if(!string.IsNullOrEmpty(Model.ModelTypeNamespace)) { #>
    using <#= Model.ModelTypeNamespace #>;
    using <#= Model.ModelTypeNamespace #>.Repositories;
<# } #>
<# if((!string.IsNullOrEmpty(Model.RepositoriesNamespace)) && (Model.RepositoriesNamespace != Model.ModelTypeNamespace)) { #>
    using <#= Model.RepositoriesNamespace #>;
<# } #>   
<#  
    var modelType = (CodeType)Model.ModelType; 
    var modelName = modelType.Name; 
    var modelNamePlural = Model.ModelTypePluralized; 
    var modelVariable = modelName.ToLower(); 
    var relatedEntities = ((IEnumerable)Model.RelatedEntities).OfType<RelatedEntityInfo>();
    var primaryKeyProperty = modelType.VisibleMembers().OfType<CodeProperty>().Single(x => x.Name == Model.PrimaryKey);
    var routingName = Regex.Replace(Model.ControllerName, "Controller$", "", RegexOptions.IgnoreCase);
#>
    public class <#= Model.ControllerName #> : Controller
    {
<# foreach(var repository in Repositories.Values) { #>
        private readonly I<#= repository.RepositoryTypeName #> _<#= repository.VariableName #>;
<# } #>

        // If you are using Dependency Injection, you can delete the following constructor
        public <#= Model.ControllerName #>()
            : this(<#= String.Join(", ", Repositories.Values.Select(x => "new " + x.RepositoryTypeName + "()")) #>)
        {
        }

        public <#= Model.ControllerName #>(<#= String.Join(", ", Repositories.Values.Select(x => "I" + x.RepositoryTypeName + " " + x.VariableName)) #>)
        {
<# foreach(var repository in Repositories.Values) { #>
            this._<#= repository.VariableName #> = <#= repository.VariableName #>;
<# } #>
        }

        // GET: /<#= routingName #>/
        public ViewResult Index()
        {
<#
    var propertiesToInclude = relatedEntities.Select(relation => relation.LazyLoadingProperty).Where(x => x != null);
    var includeExpression = String.Join(", ", propertiesToInclude.Select(x => String.Format("{0} => {0}.{1}", modelVariable, x.Name)));
    if (!string.IsNullOrEmpty(includeExpression)) {
        includeExpression = "Including(" + includeExpression + ")";
    }
#>
            return this.View(this._<#= Repositories[modelType.FullName].VariableName #>.All<#= includeExpression #>);
        }

        // GET: /<#= routingName #>/Create
        public ActionResult Create()
        {
<# foreach(var relatedEntity in relatedEntities.Where(x => x.RelationType == RelationType.Parent)) { #>
            this.ViewBag.Possible<#= relatedEntity.RelationNamePlural #> = this._<#= Repositories[relatedEntity.RelatedEntityType.FullName].VariableName #>.All;
<# } #>
            return this.View();
        } 

        // POST: /<#= routingName #>/Create
        [HttpPost]
        public ActionResult Create(<#= modelName #> <#= modelVariable #>)
        {
            if (ModelState.IsValid) {
                this._<#= Repositories[modelType.FullName].VariableName #>.InsertOrUpdate(<#= modelVariable #>);
                this._<#= Repositories[modelType.FullName].VariableName #>.Save();
                return this.RedirectToAction("Index");
            } 
            
<# foreach(var relatedEntity in relatedEntities.Where(x => x.RelationType == RelationType.Parent)) { #>
            this.ViewBag.Possible<#= relatedEntity.RelationNamePlural #> = this._<#= Repositories[relatedEntity.RelatedEntityType.FullName].VariableName #>.All;
<# } #>
            return this.View();
        }
        
        // GET: /<#= routingName #>/Edit/{id}
        public ActionResult Edit(<#= primaryKeyProperty.Type.AsString #> id)
        {
<# foreach(var relatedEntity in relatedEntities.Where(x => x.RelationType == RelationType.Parent)) { #>
            this.ViewBag.Possible<#= relatedEntity.RelationNamePlural #> = this._<#= Repositories[relatedEntity.RelatedEntityType.FullName].VariableName #>.All;
<# } #>
            return this.View(this._<#= Repositories[modelType.FullName].VariableName #>.Find(id));
        }

        // POST: /<#= routingName #>/Edit/{id}
        [HttpPost]
        public ActionResult Edit(<#= modelName #> <#= modelVariable #>)
        {
            if (ModelState.IsValid) {
                this._<#= Repositories[modelType.FullName].VariableName #>.InsertOrUpdate(<#= modelVariable #>);
                this._<#= Repositories[modelType.FullName].VariableName #>.Save();
                return this.RedirectToAction("Index");
            } 

<# foreach(var relatedEntity in relatedEntities.Where(x => x.RelationType == RelationType.Parent)) { #>
            this.ViewBag.Possible<#= relatedEntity.RelationNamePlural #> = this._<#= Repositories[relatedEntity.RelatedEntityType.FullName].VariableName #>.All;
<# } #>
            return this.View();
        }

        // GET: /<#= routingName #>/Delete/{id}
        public ActionResult Delete(<#= primaryKeyProperty.Type.AsString #> id)
        {
            return this.View(this._<#= Repositories[modelType.FullName].VariableName #>.Find(id));
        }

        // POST: /<#= routingName #>/Delete/{id}
        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(<#= primaryKeyProperty.Type.AsString #> id)
        {
            this._<#= Repositories[modelType.FullName].VariableName #>.Delete(id);
            this._<#= Repositories[modelType.FullName].VariableName #>.Save();

            return this.RedirectToAction("Index");
        }
    }
}
<#+
class RepositoryInfo {
    public string RepositoryTypeName { get; set; }
    public string VariableName { get; set; }
}

IDictionary<string, RepositoryInfo> _repositories;
IDictionary<string, RepositoryInfo> Repositories {
    get {
        if (_repositories == null) {
            var relatedEntities = ((IEnumerable)Model.RelatedEntities).OfType<RelatedEntityInfo>();
            var relatedTypes = relatedEntities.Where(x => x.RelationType == RelationType.Parent).Select(x => x.RelatedEntityType).Distinct();
            _repositories = relatedTypes.ToDictionary(
                relatedType => relatedType.FullName,
                relatedType => new RepositoryInfo { RepositoryTypeName = relatedType.Name + "Repository", VariableName = relatedType.Name.ToLower() + "Repository" }
            ); 
            _repositories[((CodeType)Model.ModelType).FullName] = new RepositoryInfo { RepositoryTypeName = Model.Repository, VariableName = ((CodeType)Model.ModelType).Name.ToLower() + "Repository" };
        }
        return _repositories;
    }
}
#>

Файл: MvcScaffolding.RazorView\Index.cs.t4

Уберем ссылки на указанное выше Действие Details, которые выглядят следующим образом:

@Html.ActionLink("Details", "Details", new { id=item.<#= Model.PrimaryKeyName #> }) |
<#@ Template Language="C#" HostSpecific="True" Inherits="DynamicTransform" #>
<#@ Output extension="cshtml" #>
<#@ assembly name="System.ComponentModel.DataAnnotations" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data.Entity" #>
<#@ assembly name="System.Data.Linq" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.ComponentModel.DataAnnotations" #>
<#@ import namespace="System.Data.Linq.Mapping" #>
<#@ import namespace="System.Data.Objects.DataClasses" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<# var viewDataType = (EnvDTE.CodeType) Model.ViewDataType; #>
<# if(viewDataType != null) { #>
@model IEnumerable<<#= viewDataType.FullName #>>
<# } #>
@{
    ViewBag.Title = "<#= Model.ViewName #>";
<# if (!String.IsNullOrEmpty(Model.Layout)) { #>
    Layout = "<#= Model.Layout #>";
<# } #>
}

<h2><#= Model.ViewName #></h2>

<p>@Html.ActionLink("Create New", "Create")</p>

<table>
    <tr>
        <th></th>
<#
List<ModelProperty> properties = GetModelProperties(Model.ViewDataType, true);
foreach (ModelProperty property in properties) {
    if (!property.IsPrimaryKey && !property.IsForeignKey) {
#>
        <th><#= property.Name #></th>
<#
    }
}
#>
    </tr>

@foreach (var item in Model) {
    <tr>
<# if (!String.IsNullOrEmpty(Model.PrimaryKeyName)) { #>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.<#= Model.PrimaryKeyName #> }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.<#= Model.PrimaryKeyName #> })
        </td>
<# } else { #>
        <td>
            @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
            @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
        </td>
<# } #>
<#  
foreach (ModelProperty property in properties) {
    if (!property.IsPrimaryKey && !property.IsForeignKey) {
#>
        <td>@<#= property.ValueExpression.Replace("Model.", "item.") #></td>
<#
    }
}
#>
    </tr>
}

</table>


<#+
// Describes the information about a property on the model
class ModelProperty {
    public string Name { get; set; }
    public string ValueExpression { get; set; }
    public EnvDTE.CodeTypeRef Type { get; set; }
    public bool IsPrimaryKey { get; set; }
    public bool IsForeignKey { get; set; }
    public bool IsReadOnly { get; set; }
}

// Change this list to include any non-primitive types you think should be eligible to be edited using a textbox
static Type[] bindableNonPrimitiveTypes = new[] {
    typeof(string),
    typeof(decimal),
    typeof(Guid),
    typeof(DateTime),
    typeof(DateTimeOffset),
    typeof(TimeSpan),
};

// Call this to get the list of properties in the model. Change this to modify or add your
// own default formatting for display values.
List<ModelProperty> GetModelProperties(EnvDTE.CodeType typeInfo, bool includeUnbindableProperties) {
    List<ModelProperty> results = GetEligibleProperties(typeInfo, includeUnbindableProperties);
    
    foreach (ModelProperty prop in results) {
        if (prop.Type.UnderlyingTypeIs<double>() || prop.Type.UnderlyingTypeIs<decimal>()) {
            prop.ValueExpression = "String.Format(\"{0:F}\", " + prop.ValueExpression + ")";
        }
        else if (prop.Type.UnderlyingTypeIs<DateTime>()) {
            prop.ValueExpression = "String.Format(\"{0:g}\", " + prop.ValueExpression + ")";
        }
        else if (!IsBindableType(prop.Type)) {
            prop.ValueExpression = GetValueExpression("Model." + prop.Name, (EnvDTE.CodeType)prop.Type.CodeType);
        }
    }

    return results;
}

// Change this list to include the names of properties that should be selected to represent an entity as a single string
static string[] displayPropertyNames = new[] { "Name", "Title", "LastName", "Surname", "Subject", "Count" };

string GetValueExpression(string propertyExpression, EnvDTE.CodeType propertyType) {
    if (propertyType != null) {
        var chosenSubproperty = propertyType.DisplayColumnProperty() ?? propertyType.FindProperty(displayPropertyNames);
        if (chosenSubproperty != null) {
            var toStringSuffix = chosenSubproperty.Type.AsFullName == "System.String" ? "" : ".ToString()";
            return String.Format("({0} == null ? \"None\" : {0}.{1}{2})", propertyExpression, chosenSubproperty.Name, toStringSuffix);
        }
    }
    return "Html.DisplayTextFor(_ => " + propertyExpression + ").ToString()";
}

// Helper
List<ModelProperty> GetEligibleProperties(EnvDTE.CodeType typeInfo, bool includeUnbindableProperties) {
    List<ModelProperty> results = new List<ModelProperty>();
    if (typeInfo != null) {
        foreach (var prop in typeInfo.VisibleMembers().OfType<EnvDTE.CodeProperty>()) {
            if (prop.IsReadable() && !prop.HasIndexParameters() && (includeUnbindableProperties || IsBindableType(prop.Type))) {
                results.Add(new ModelProperty {
                    Name = prop.Name,
                    ValueExpression = "Model." + prop.Name,
                    Type = prop.Type,
                    IsPrimaryKey = Model.PrimaryKeyName == prop.Name,
                    IsForeignKey = ParentRelations.Any(x => x.RelationProperty == prop),
                    IsReadOnly = !prop.IsWriteable()
                });
            }
        }
    }

    return results;
}

IEnumerable<RelatedEntityInfo> ParentRelations {
    get { return ((IEnumerable)Model.RelatedEntities).OfType<RelatedEntityInfo>().Where(x => x.RelationType == RelationType.Parent); }
}

// Helper
bool IsBindableType(EnvDTE.CodeTypeRef type) {
    return type.UnderlyingIsPrimitive() || bindableNonPrimitiveTypes.Any(x => type.UnderlyingTypeIs(x));
}
#>

Файл: T4Scaffolding.EFRepository\Repository.cs.t4

Здесь изменения, кроме стиля исходного кода, коснутся пространств имен.

<#@ template language="C#" HostSpecific="True"  inherits="DynamicTransform" #>
<#@ assembly name="System.Data.Entity" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="EnvDTE" #>
<#@ Output Extension="cs" #>
namespace <#= Model.RepositoryNamespace #>.Repositories
{ 
    using System;
    using System.Data;
    using System.Data.Entity;
    using System.Linq;
    using System.Linq.Expressions;
    using <#= Model.ModelTypeNamespace #>;
    using <#= Model.ModelTypeNamespace #>.DbContext;
    <# foreach(var ns in new[] { Model.ModelTypeNamespace, Model.DbContextNamespace }.Where(x => !string.IsNullOrEmpty(x) && (x != Model.RepositoryNamespace)).Distinct()) { #>
    using <#= ns #>;
    <# } #>

<# 
    var modelType = (CodeType)Model.ModelType; 
    var modelName = modelType.Name; 
    var modelNamePlural = Model.ModelTypePluralized; 
    var contextName = ((CodeType)Model.DbContextType).Name; 
    var primaryKeyProperty = modelType.VisibleMembers().OfType<CodeProperty>().Single(x => x.Name == Model.PrimaryKey);
    var isObjectContext = ((CodeType)Model.DbContextType).IsAssignableTo<System.Data.Objects.ObjectContext>();
#>
    public interface I<#= modelName #>Repository
    {
        IQueryable<<#= modelName #>> All { get; }
        IQueryable<<#= modelName #>> AllIncluding(params Expression<Func<<#= modelName #>, object>>[] includeProperties);
        <#= modelName #> Find(<#= primaryKeyProperty.Type.AsString #> id);
        void InsertOrUpdate(<#= modelName #> <#= modelName.ToLower() #>);
        void Delete(<#= primaryKeyProperty.Type.AsString #> id);
        void Save();
    }

    public class <#= modelName #>Repository : I<#= modelName #>Repository
    {
        private readonly <#= contextName #> _context = new <#= contextName #>();

        public IQueryable<<#= modelName #>> All
        {
            get { return this._context.<#= modelNamePlural #>; }
        }

        public IQueryable<<#= modelName #>> AllIncluding(params Expression<Func<<#= modelName #>, object>>[] includeProperties)
        {
            IQueryable<<#= modelName #>> query = this._context.<#= modelNamePlural #>;
            foreach (var includeProperty in includeProperties) {
                query = query.Include(includeProperty);
            }

            return query;
        }

        public <#= modelName #> Find(<#= primaryKeyProperty.Type.AsString #> id)
        {
<# if(isObjectContext) { #>
            return this._context.<#= modelNamePlural #>.Single(x => x.<#= Model.PrimaryKey #> == id);
<# } else { #>
            return this._context.<#= modelNamePlural #>.Find(id);
<# } #>
        }

        public void InsertOrUpdate(<#= modelName #> <#= modelName.ToLower() #>)
        {
            if (<#= modelName.ToLower() #>.<#= Model.PrimaryKey #> == default(<#= primaryKeyProperty.Type.AsString #>)) {
                // New entity
<# if(primaryKeyProperty.Type.AsString == "System.Guid") { #>
                <#= modelName.ToLower() #>.<#= primaryKeyProperty.Name #> = Guid.NewGuid();
<# } #>
<# if(isObjectContext) { #>
                this._context.<#= modelNamePlural #>.AddObject(<#= modelName.ToLower() #>);
<# } else { #>
                this._context.<#= modelNamePlural #>.Add(<#= modelName.ToLower() #>);
<# } #>
            } else {
                // Existing entity
<# if(isObjectContext) { #>
                this._context.<#= modelNamePlural #>.Attach(<#= modelName.ToLower() #>);
                this._context.ObjectStateManager.ChangeObjectState(<#= modelName.ToLower() #>, EntityState.Modified);
<# } else { #>
                this._context.Entry(<#= modelName.ToLower() #>).State = EntityState.Modified;
<# } #>
            }
        }

        public void Delete(<#= primaryKeyProperty.Type.AsString #> id)
        {
<# if(isObjectContext) { #>
            var <#= modelName.ToLower() #> = this._context.<#= modelNamePlural #>.Single(x => x.<#= Model.PrimaryKey #> == id);
            this._context.<#= modelNamePlural #>.DeleteObject(<#= modelName.ToLower() #>);
<# } else { #>
            var <#= modelName.ToLower() #> = this._context.<#= modelNamePlural #>.Find(id);
            this._context.<#= modelNamePlural #>.Remove(<#= modelName.ToLower() #>);
<# } #>
        }

        public void Save()
        {
            this._context.SaveChanges();
        }
    }
}

Файл: T4Scaffolding.EFDbContext\DbContext.cs.t4

В этой заготовке сделано только одно изменение: директива using внесена внутрь namespace.

<#@ Template Language="C#" HostSpecific="True" Inherits="DynamicTransform" #>
<#@ Output Extension="cs" #>
namespace <#= Model.DbContextNamespace #>
{
    using System.Data.Entity;

    public class <#= Model.DbContextType #> : DbContext
    {
        // You can add custom code to this file. Changes will not be overwritten.
        // 
        // If you want Entity Framework to drop and regenerate your database
        // automatically whenever you change your model schema, add the following
        // code to the Application_Start method in your Global.asax file.
        // Note: this will destroy and re-create your database with every model change.
        // 
        // System.Data.Entity.Database.SetInitializer(new System.Data.Entity.DropCreateDatabaseIfModelChanges<<#= Model.DbContextNamespace #>.<#= Model.DbContextType #>>());

    }
}

Теперь, когда созданы новые заготовки, перейдем к созданию Контроллеров и Представлений.


Исходный код проекта (C#, Visual Studio 2010): mvc3-in-depth-basics-06.zip

Комментарии (7) -

Артур 17.06.2011 23:09:18

>директива using внесена внутрь namespace

в чем фишка?

Такой подход помогает избежать путаницы в пространствах имен в некоторых ситуациях. Давно как-то сталкивался, с тех пор привычка.

@ Артур:

А если ты его в namespace не пропишешь, то студия не сможет DbContext найти...я поленился переносить using и некоторое время имел головняк в DbContext

Снова здравствуйте. У меня вопрос. После внимательного просмотра с сравнения кода вашего примера и того что получилось у меня нашел вот какие отличия:
Во всех файлах из папки Repositories (BookDetailsRepository.cs, LanguageRepository.cs, PublisherRepository.cs, TagRepository.cs) пришлось руками менять namespace BookCatalog.Models  на namespace BookCatalog.Models.Repositories
и еще добавлять
using BookCatalog.Models;
using BookCatalog.Models.DbContext;
Это так и надо или я что-то неправильно сделал???

@ Andriy: Эти изменения (в шаблоне) описаны после заголовка "Вносим изменения". После чего будут генерироваться файлы сразу с нужными using.

Евгений 18.07.2012 22:23:30

Андрей, а я правильно понимаю, что при изменении заготовок
мы, теоретически, должны получить такой эффект,
что при формировании View из контекстного меню в инспекторе решения (solution explorer) - через диалог Add View, с указанием ViewEngine = Razor -
я получу представление уже по отредактированному шаблону ?
(Иными словами, отредактировав шаблон через команды консоли NuGet,
я могу другому программисту эту консоль уже не показывать,
а просто поручить создать представления стандартным, удобным путем,
но они будут уже по отредактированному мной шаблону ?)

@ Евгений: В принципе да, т.к. полученные заготовки появляются в стандартном диалоге Add Controller (в проекте, в который они установлены).

Добавить комментарий