Olá Habr! Nosso colega, Scott Hanselman, acredita que, como parte do aprendizado de uma linguagem de programação, é importante não apenas codificar e praticar a escrita, mas também aprender o código de outra pessoa. "Leia o código de outra pessoa", diz Scott, e cita material útil que encontrou no trabalho de seu colega. Mais detalhes sob o corte!
Passo a palavra para Scott Hanselman . Você concorda com ele?
A melhor abordagem para aprender uma linguagem de programação não é apenas escrever mais código, mas também
familiarizar-se com seus exemplos ! Nem sempre serão exemplos de código exemplar e muito do que você vê não será útil, mas é uma ótima maneira de ampliar seus horizontes.
Acredito que de fato a leitura do código não recebe a devida atenção. Talvez não haja bases de código limpas suficientes.
Fiquei agradavelmente surpreso quando descobri uma base de código chamada
Universidade Jimmy Bogard
Contoso .
Este repositório tem muito material bom, mas não direi que li tudo e com a mesma atenção que gostaríamos. Para estudar tudo em detalhes, você precisa passar o dia inteiro. No entanto, gostei de alguns pontos e os tomei nota. Peças individuais de código são claramente feitas no estilo de Jimmy, como ele as escreveu por si mesmo.
Isso não é uma censura. Com o tempo, todos nós acumulamos modelos, criamos bibliotecas e desenvolvemos nossos próprios estilos arquitetônicos. Gosto do fato de Jimmy ter colecionado desenvolvimentos interessantes feitos por ele ou com sua participação ao longo dos anos e preparado um bom material de leitura. Jimmy observa que o
ContosoUniversityDotNetCore-Pages tem muitas coisas úteis:
Clonagem e montagem funcionam muito bem
Você ficará surpreso com o quão baixo eu às vezes abaixo a barra. Muitas vezes clono o repositório git de outra pessoa que não foi testado em nenhum lugar. E recebo um bônus por baixar no build.ps1 tudo o que é necessário.
O .NET Core 2.x já está instalado no meu
sistema , o build.ps1 recebe os pacotes necessários e cria completamente o código.
Há muitas opiniões sobre este projeto. E isso é ótimo, porque é assim que eu aprendo sobre métodos e ferramentas que eu não usei antes. Se alguém usa uma abordagem não padrão, então entre as ferramentas padrão não há necessidade!
- Build.ps1 usa um estilo de script de compilação retirado do PSake , uma ferramenta de automação de compilação do PowerShell.
- Coloca a montagem em uma pasta com o nome padrão ./artifacts.
- Build.ps1 usa Roundhouse , um utilitário de migração de banco de dados para .NET que usa arquivos e versões SQL criados usando a ferramenta de controle de versão projectroundhouse .
- Ele está configurado para integração contínua ao AppVeyor , o excelente sistema de CI / CD que eu mesmo uso.
- Ela usa a ferramenta Octo.exe do OctopusDeploy para compactar artefatos.
Código ordenado e claro
Na minha opinião, todo o código é muito fácil de ler. Comecei com o Startup.cs para entender apenas o que o middleware está sendo usado.
public void ConfigureServices(IServiceCollection services) { services.AddMiniProfiler().AddEntityFramework(); services.AddDbContext<SchoolContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddAutoMapper(typeof(Startup)); services.AddMediatR(typeof(Startup)); services.AddHtmlTags(new TagConventions()); services.AddMvc(opt => { opt.Filters.Add(typeof(DbContextTransactionPageFilter)); opt.Filters.Add(typeof(ValidatorPageFilter)); opt.ModelBinderProviders.Insert(0, new EntityModelBinderProvider()); }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_1) .AddFluentValidation(cfg => { cfg.RegisterValidatorsFromAssemblyContaining<Startup>(); }); }
Aqui eu vejo as bibliotecas e auxiliares usados, por exemplo, AutoMapper, MediatR e HtmlTags. Em seguida, posso entrar em seções separadas e estudar cada ferramenta.
Miniprofiler
Eu sempre gostei da ferramenta
MiniProfiler . Esse tesouro secreto do .NET foi criado por um longo tempo e é sempre útil no trabalho.
Eu o mencionei em 2011! Ele está invisivelmente presente na sua página da web e fornece dados REALMENTE úteis sobre o comportamento do site e os principais valores de tempo de execução.

É aconselhável usá-lo com o EF Core para ver também o código SQL gerado. E tudo é incorporado no site à medida que é criado.

Apenas ótimo!
Limpar testes de unidade
Jimmy usa o XUnit e vejo o arquivo
IntegrationTestBase na lista
. Não entendo alguns pontos, por exemplo, a operação do arquivo
SliceFixture . Tomou uma nota para entender tudo. É improvável que a criação de uma nova biblioteca auxiliar de teste seja lançada aqui: abordagem universal e séria demais para usá-la neste modelo.
Jimmy usa o padrão
CQRS (Command Query Responsibility Segregation). No início, o comando Criar é criado e executado, e uma consulta é executada para confirmar os resultados. Tudo está muito claro, temos um teste muito isolado.
[Fact] public async Task Should_get_edit_details() { var cmd = new Create.Command { FirstMidName = "Joe", LastName = "Schmoe", EnrollmentDate = DateTime.Today }; var studentId = await SendAsync(cmd); var query = new Edit.Query { Id = studentId }; var result = await SendAsync(query); result.FirstMidName.ShouldBe(cmd.FirstMidName); result.LastName.ShouldBe(cmd.LastName); result.EnrollmentDate.ShouldBe(cmd.EnrollmentDate); }
Validação de fluido
A validação fluente é uma biblioteca útil para criar regras claras de validação com forte controle de tipo. Jimmy o usa em qualquer lugar e obtém um código de verificação extremamente claro.
public class Validator : AbstractValidator<Command> { public Validator() { RuleFor(m => m.Name).NotNull().Length(3, 50); RuleFor(m => m.Budget).NotNull(); RuleFor(m => m.StartDate).NotNull(); RuleFor(m => m.Administrator).NotNull(); } }
Soluções úteis
Vamos ver quais métodos a extensão do projeto C # usa pelo autor. Isso mostra o que, na opinião dele, falta na funcionalidade básica. O método permite retornar dados no formato JSON a partir do Razor Pages.
public static class PageModelExtensions { public static ActionResult RedirectToPageJson<TPage>(this TPage controller, string pageName) where TPage : PageModel { return controller.JsonNet(new { redirect = controller.Url.Page(pageName) } ); } public static ContentResult JsonNet(this PageModel controller, object model) { var serialized = JsonConvert.SerializeObject(model, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); return new ContentResult { Content = serialized, ContentType = "application/json" }; } }
Paginatedlist
Eu sempre me perguntei o que fazer com classes auxiliares como PaginatedList. Muito pequeno para embalagem, muito específico para incorporação. O que você acha?
public class PaginatedList<T> : List<T> { public int PageIndex { get; private set; } public int TotalPages { get; private set; } public PaginatedList(List<T> items, int count, int pageIndex, int pageSize) { PageIndex = pageIndex; TotalPages = (int)Math.Ceiling(count / (double)pageSize); this.AddRange(items); } public bool HasPreviousPage { get { return (PageIndex > 1); } } public bool HasNextPage { get { return (PageIndex < TotalPages); } } public static async Task<PaginatedList<T>> CreateAsync(IQueryable<T> source, int pageIndex, int pageSize) { var count = await source.CountAsync(); var items = await source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync(); return new PaginatedList<T>(items, count, pageIndex, pageSize); } }
Continuo explorando todas as fontes de código que encontro. Tomo nota das coisas que gosto, anote o que não sei ou não entendo e faço uma lista de tópicos para leitura. Eu aconselho você a fazer o mesmo! Obrigado,
Jimmy , por escrever
um ótimo modelo de código que podemos ler e aprender!