You are on page 1of 12

3/28/2017 WritingaBlogEngineinASP.

NETCoreCodeProject

Writing a Blog Engine in ASP.NET Core


Tyler Rhodes, 27 Mar 2017 MIT

5.00 10 votes

Reflections on writing a simple blog engine in ASP.NET Core with Entity Framework Core

Live site running the blog


Download source 1,914 Kb

Introduction
This is my first article on CodeProject. My background is a mix of Network/Systems Engineering and Software Development. I first
learned to program in QBasic when I was still in middle school and since then I've written some trivial and some not trivial programs in
languages like JavaScript, C and C#. I personally find programming to be rewarding and enjoy solving technical problems. Unfortunately,
sometimes I feel like I do more reading about programming than I do programming, so I figured I would reverse the trend a little bit
and wound up writing a blogging engine so that I could write about programming.

So about two or three months ago I started writing my blogging engine. Along the way it grew into a fairly substantial project, and it
got to the point where I came to the conclusion that it might be helpful to the community to share it. It's far from perfect, but it has
some nice features like being able to categorize blog posts and a functional search capability, and it's gotten to the point where it's
"good enough" to share.

This article is somewhat of a retrospective on my experience writing that blog engine using C# and ASP.NET Core. I'm going to go over
some of the design considerations that played into which technology I chose, how it runs, where I feel I've made some mistakes, what I
plan on changing, and what I've learned along the way.

I'm don't consider myself an expert in ASP.NET Core, although after this project I've certainly learned a little bit. My hope would be in
reading this article you can see some of the things that I ran into choosing this technology, and see the impact from some of the design
decisions that were made.

I called the blog engine Bagombo because I had registered the domain bagombo.org a long time ago and because I had read Bagombo
Snuff Box. Working in software development for a while now it seems like naming things jointly is sometimes as hard as writing the
code, and it was nice to be able to just pick a name without having to consult too many people :

Bagombo as it is now isn't really a finished project, much like any software. But it got to the point where I have started to use it and I
thought putting the source code out there and just releasing it may help someone starting out with ASP.NET Core and Entity Framework
Core get started writing their own blog engine. I released it under the MIT license, so people are free to do whatever they want with it.

Below are some of the features of the blog engine:

Support for categorizing posts by Features or Category


Support for multiple authors
Local or Twitter authentication
Full text search of blog posts
Builtin editor for editing a post in markdown with preview

I'll talk about the design and implemention of these and what I learned along the way. I'm going to focus on the backend ASP.NET Core
and EF Core parts of the code though, and won't address any of the front end design except to say I used basic HTML, Bootstrap and

https://www.codeproject.com/Articles/1178519/WritingaBlogEngineinASPNETCore?display=Print 1/12
3/28/2017 WritingaBlogEngineinASP.NETCoreCodeProject

some JavaScript. It doesn't rely on any fancy JavaScript libraries like Angular or Backbone, it just uses a little jQuery and the highlight.js
library for syntax highlighting.

First I'll go over how I ultimately wound up with the technology stack that I did.

The Technology Stack


I decided to write my blog engine in ASP.NET Core because when I heard about it I was stoked. .NET Core ran on the Mac and I didn't
need to use Mono to get it to work. It came straight from Microsoft and with the neat new Visual Studio Code editor I thought it was
awesome, plus I do some C# programming at work so I figured I would take the opportunity to write my blog engine using the latest
and greatest and increase my skillset a bit.

Below are some of the initial reasons and thoughts I had for writing the blog in ASP.NET Core and not something like Node.js.

First, I like C#.


Second, ASP.NET Core MVC was released as open source, so it's possible to dig into the source code and go as far into it as I
have the time or inclination to do. I thought this was a big draw.
Third, initially I planned on using Dapper as my ORM and MySQL so I could do all the development on my Mac and then when it
came time to put it into production I could use a Linux server. This all changed though a little later.
Fourth, did I mention I thought I could use my Mac to do all the development on?

So my initial design thoughts based upon what I had heard about the software were as follows. I would do all of my development on the
Mac and then move it to an Ubuntu or CentOS Linux server when I wanted to put it in production. I even thought about Docker but
haven't quite gotten it that far. I could run MySQL on my Mac using Homebrew and when it came time to move it over it would be easy
to get it running on Linux.

I liked MySQL from some projects I had used it for a while ago, and I like open source software especially when it's free and works well. I
use Oracle 11g at work too and I have to say it works pretty well too, and since this was sort of an educational project I wanted to use
the free Oracle XE with it, but at the time Oracle hadn't even announced whether or not they were going to support .NET Core. This has
changed from what I understand now and they are going to support .NET Core from what I have read. But I liked MySQL and this was
just a personal project so I figured I would use that. SQL Server isn't released on Linux yet from what I understand ... maybe there is a
beta or something out, but I can run MySQL on my Mac!!

So I was set, ASP.NET Core, Dapper, MySQL, NGINX to reverse proxy it, Linux as the server, run it on AWS. Off I went ...

And then I ran into the first "gotcha". I needed authentication for my blog. Now, this is probably where I've either gone in the right or
wrong direction from the start. Authentication is one of those things where I tend to lean towards taking the safe route, and being new
with ASP.NET Core I didn't feel very comfortable rolling my own authentication because I really didn't know what I was doing with it. I
mean, the worst that could happen is that someone hacks into my personal blog and destroys it and I have to restore it from backup,
not the end of the world. But this was a learning exercise.

So I started digging through the Microsoft documentation for ASP.NET Core and while I think it's pretty good for the most part, I found
the section on authentication to be lacking. But it talked about using Identity, which is as I think they put it, a "membership system"
which allows you to use local authentication as well as fairly easily plug and authenticate using Twitter, Facebook, OAuth2 and things like
that. I have a twitter account that I use to follow the news @itcheeze and figured setting up the Twitter authentication would be nice. I
also plan to implement a comments feature for the blog, and if I get any readers making them sign up and remember another password
is not something I wanted to do. I also had the book Pro ASP.NET Core MVC by Adam Freeman which was somewhere near 1000 pages
long and had three chapters on Identity.

So, I thought, it seemed like a good idea to use Identity. And overall I think it was the right choice still. In the end I was able to plug it in
and get it working without much trouble. I even got the Twitter authentication to work without fighting too much with it which was nice.
I haven't plugged in any other external authentication but based upon my experience with Twitter I think that getting that to work won't
be a stretch.

But it did throw the first wrinkle into how I had originally planned to do things. Identity, for anyone who wants to use it out of the box
and just run with it, relies on Entity Framework Core, or EF Core. Ugh. I hadn't planned on using EF Core. My nice 1000 page Pro
ASP.NET Core book had exactly zero chapters dedicated to EF Core. I didn't want to have to use two ORM libraries with my blog, and I
had already done a little proof of concept fiddling around with Dapper and MySQL and was comfortable with that approach. Now I had
to deal with EF Core. Although there was another option, Identity is open source! So I spent probably 34 hours digging through the
source code for Identity. I came to the determination that it would be possible to implement some key interfaces for user stores and role
stores and effectively factor EF Core out of the equation.

https://www.codeproject.com/Articles/1178519/WritingaBlogEngineinASPNETCore?display=Print 2/12
3/28/2017 WritingaBlogEngineinASP.NETCoreCodeProject

I gave it some serious thought. Ultimately I think that to do it I would have had to master Identity a little more than I wanted to. And
looking at the classes that implemented those key interfaces for the stores which made use of EF Core, I decided it was a little hard to
pick apart everything it was doing since I didn't know EF Core at all. What to do? This was really the point in my design where all of the
tech I had picked out to started to change direction a bit. Little did I know it that my Mac based development plan was going to change.
It hasn't been all bad though. I am fond of my 2014 Macbook Pro though. It's a kickass computer ... as I write this on Windows running
on VMware Fusion ...

I'll go a little more into my experience and the design of my model/data layer for the blog under the design section. I want to keep
going with how I ultimately ended up with a far different stack of technology than I originally thought I would. Granted, some of the
things that influenced these changes have probably changed by now, but I was starting to make headway, and I wanted my blog
software. Bagombo wasn't going to write itself.

So, to use Identity, I had to use EF Core as far as I know this is the only way to do it without implementing the backing stores it requires,
I searched on Google for a long time trying to find someone who has done it without finding anyone, and I'm considering it for a
project someday.

Okay, so my project has a new dependency. At this point I do a little research on EF Core and start to warm up to the idea. I can't find a
ton of documentation online, and I still don't claim to understand all that it does and how it works. Also, using what it calls a "Code
First" approach to modeling your data, it magically creates the database and all of the schema that you need, based upon your code.
Well it isn't quite magic, and it turns out that, being a new piece of software, not every database provider has a finished EF Core
provider. I tried the official MySQL provider and also one by a company called Sapient I think, and spent a while fighting with Nuget
packages and playing around with different releases to try to get EF Core to do its magic and create my database and tables. I got no
love. I tried it with SQLite and it worked beautifully. Hmm, at least at that point I knew that it wasn't something with my code or my
fingers typing stuff in. I'll stick with that, I read that some people had gotten it to work with Sapient somewhere on the internet, but I
couldn't.

So my first hurdle. In all honesty, I probably could have used SQLite for my project and been just fine. But I actually don't know SQLite
that well and I really didn't want to use it. I mean, someday my blog is going to have all of these readers and I'll make a ton of money
with it and all of that stuff and then what would I do? Well I gave it some serious consideration because I am kind of lazy. But it just
didn't sit right with what I wanted to do. Hmmmmm. So that meant ... SQL Server. And that meant ... Windows. Well not all was lost. I
could still do all of my development on my Mac and just point my database connection to a Windows VM or take the time and run
Docker or something like that and all would be right with the world. I'm at the point where I'm not really too picky about what it would
run on in production as long as it works well.

But then I ran into wrinkle number two, which wasn't as big really, but when put together with wrinkle number one, well ...

Visual Studio Code which I still like and use for Go programming and Powershell scripting doesn't have Intellisense for Razor
Pages!!!!!

So I tried Visual Studio 2015 and of course, it worked pretty well there. And I'm glad that I made that switch because I kind of count that
as a requirement for development. If MySQL worked with EF Core a little better I probably would have stuck it out on the Mac. But I
figured I'd just give it a try, and wound up continuing to do my development there. By the time I was in the middle of the project Visual
Studio 2017 had just been released, so I even made the plunge of upgrading my package.json project to the new csproj based projects,
and finished off my coding with that. I find it to be a nice development environment and actually enjoy using it for programming. I do
like Visual Studio Code a lot though and find that I still have space for it.

So, original plan: ASP.NET Core, Dapper, MySQL, NGINX to reverse proxy it, Linux as the server, run it on AWS. Develop on my Mac.
Actual plan: ASP.NET Core, EF Core, SQL Server 2016 Express, IIS to reverse proxy it, Windows Server 2016, run it on AWS. Develop on
Windows.

Design
I found that at this point, most of the following design was primarily driven by my first choice, which was using ASP.NET Core MVC. If
you're going to use it, I think it makes sense to follow it's conventions. Otherwise you'll be fighting the grain and it probably won't work
that well for you. I'd never used it before, and I'm not going to go over every line of code I wrote or anything like that. In all honesty I
had to read a whole book and search the internet a lot to get it to work, and it would take a whole book to describe how everything
works.

I'll say this about it though. I knew C# pretty well, but everything else in ASP.NET Core was new to me. I'm pretty good at picking up
new technologies quickly, and while this is just a basic blog engine, it took 23 months of part time work to get it going. I consider it at
0.2 Alpha right now jokingly.

https://www.codeproject.com/Articles/1178519/WritingaBlogEngineinASPNETCore?display=Print 3/12
3/28/2017 WritingaBlogEngineinASP.NETCoreCodeProject

I meant this article as a retrospective on my experience writing Bagombo, but I do want to include a little bit about the code and what I
discovered along the way.

ASP.NET Core MVC has the MVC in it's title for a reason. It stands for Model View Controller, and its the coding design paradigm that it
uses for its operations. It won't stop you from writing a lot of code that you probably shouldn't directly in your Razor pages, or
formatting a bunch of raw HTML in your Controller and dumping it down to the browser. I hate to call myself an expert, but I think you'd
be pretty silly to use MVC and then do that kind of thing. In effect I guess, you wouldn't be using MVC.

So the code for Bagombo is broken up in in a way to follow the conventions of MVC as much as possible. The core of the code that
does anything is in the controllers. I have five of them in the source code currently, and one of them, BlogApiController I plan on
removing because I basically at an early point stopped doing anything SPA like. All it does now is have a method to delete a blog post.
Right now it's kind of silly how I have it rigged up, but it responds to a post from a page form to delete a blog post, then it redirects
back to that page. It works, but I need to move that code into the Admin Controller, which would make more sense based upon the fact
that it's from an Admin Manage Posts page where this call is made. I actually don't plan on talking too much about how to use the blog
engine, because if you play around with it I think it's pretty easy to figure out. But as a side note, I made it so that only an Admin can
delete a post because I didn't write a "Are you sure you want to delete the post?" confirmation, and I didn't want posts deleted on
accident.

So the controllers in Bagombo basically handle getting data from the database, putting it into a ViewModel POCO, and returning it to
the right view. Most of the logic for the application takes place in the controllers. There is a design consideration that I made early on,
which was to not use a pattern like the Repository pattern, or something like CQRS. So I have a strong dependency currently on EF Core,
and all of the queries are coded in action methods for the controllers. For a project like this I really didn't have a problem doing that, but
I am thinking that before I consider it a 1.0 release I am going to adopt either something like the Repository or CQRS and factor this
code out so that I have less of a dependency on EF Core. At the time I didn't think about it I did kind of just whip this thing up and I
have a pretty strong dependency on EF Core anyway using Identity, unless I get really ambitious and implement the needed interfaces
so that I can use Identity without EF Core.

My model is really pretty simple. I extended the IdentityUser class which represents a user in the Identity framework into an
ApplicationUser class and added a onetoone relationship to the Author class. I have classes for blogposts, categories and
features. A feature in Bagombo is another way of organizing blogposts. I've seen some blogs where I find it really hard to find older
blogs or sort just by category. For Bagombo I thought of Features which are analogous to either chapters or topics as another way for
authors to sort their posts. There is a manytomany relationship between blogposts and categories, and blogposts to features. If you
check out the code for these classes in under the Models folder you'll see how its represented in C# code. There are also classes which
are linking tables BlogpostCategory and BlogpostFeature. EF Core needs these to establish the manytomany relationship, but from my
understanding in a future version of the software it will support this without creating these classes to represent the linking tables.

Below is an image of the data model for bagombo:

https://www.codeproject.com/Articles/1178519/WritingaBlogEngineinASPNETCore?display=Print 4/12
3/28/2017 WritingaBlogEngineinASP.NETCoreCodeProject

From this to using the Code First is a short step with EF Core. I have another class, BlogDbContext, under the Data folder, which
represents the database context. It has member variables of type DbSet<T> which represent the tables in your database. In
Bagombo's case, BlogDbContext inherits from IdentityDbContext<ApplicationUser> because of it's use of Identity.
This is where some other tables which get created for Identity in your database get hidden away, but you can find the code online if
you're curious. As far as setting up the database for Identity this is actually all thats required.

Within BlogDbContext there is a constructor which calls its base constructor. Then there is another function OnModelCreating,
which lets you use EF Core's Fluent API to configure how the tables are setup in the database and certain properties. I've used it to set
certain things like the relationships between tables, and actions to take when an entry is deleted. I find the API to be pretty readable,
and if you understand the basics about database design you'll probably see how it all comes together.

Below is the code for my BlogDbContext class. In the OnModelCreating method the relationships between the classes are
described using the EF Core Fluent API. You can also see that it inherits from IdentityDbContext<ApplicationUser> which
brings in the tables for Identity as well. I have two static methods, CreateAuthorRole and CreateAdminAccount. These are
called from the Startup class's Configure method and seed the database with an admin account specified in appsettings.json, and create
the Author role in the database if it isn't there already. This is also a handy way of creating another administrator account if you forget
the password that you specify to start with. You can also see in the OnModelCreating how I've specified what do do when an
author record is deleted. Here I've made the cascading behavior to be SetNull, so that any existing blog posts aren't deleted when an
author is removed. You can also see how the manytomany relationships are configured between blog posts and categories and
features, using the linking tables.

//BlogDbContext.csundertheDataFolderinthesolution
namespaceblog.Data
{
publicclassBlogDbContext:IdentityDbContext<ApplicationUser>
{
publicDbSet<BlogPost>BlogPosts{get;set;}
publicDbSet<Author>Authors{get;set;}
publicDbSet<Feature>Features{get;set;}
publicDbSet<BlogPostFeature>BlogPostFeature{get;set;}
publicDbSet<BlogPostCategory>BlogPostCategory{get;set;}
publicDbSet<Category>Categories{get;set;}

publicBlogDbContext(DbContextOptions<BlogDbContext>options):base(options)
{
}

protectedoverridevoidOnModelCreating(ModelBuilderbuilder)
{
base.OnModelCreating(builder);
//CustomizetheASP.NETIdentitymodelandoverridethedefaultsifneeded.
//Forexample,youcanrenametheASP.NETIdentitytablenamesandmore.
//Addyourcustomizationsaftercallingbase.OnModelCreating(builder);
builder.Entity<Author>().ToTable("Author");
builder.Entity<Author>().HasAlternateKey(e=>new{e.FirstName,e.LastName});
builder.Entity<Author>().HasOne(e=>e.ApplicationUser)
.WithOne(au=>au.Author)
.OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.SetNull);
//.OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.);

builder.Entity<ApplicationUser>().HasOne(e=>e.Author)
.WithOne(a=>a.ApplicationUser)
.HasForeignKey<Author>(a=>a.ApplicationUserId);

builder.Entity<Author>().HasIndex(a=>a.ApplicationUserId)
.IsUnique(false);

builder.Entity<Author>().HasMany(a=>a.BlogPosts)
.WithOne(bp=>bp.Author)
.IsRequired(false)
.OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.SetNull);

builder.Entity<BlogPost>().ToTable("BlogPost");

https://www.codeproject.com/Articles/1178519/WritingaBlogEngineinASPNETCore?display=Print 5/12
3/28/2017 WritingaBlogEngineinASP.NETCoreCodeProject
builder.Entity<BlogPost>().HasOne(bp=>bp.Author)
.WithMany(a=>a.BlogPosts)
.HasForeignKey("AuthorId")
.IsRequired(false);

builder.Entity<Feature>().ToTable("Feature");
builder.Entity<Category>().ToTable("Category");

builder.Entity<BlogPostFeature>().HasKey(bpf=>new{bpf.FeatureId,bpf.BlogPostId});
builder.Entity<BlogPostFeature>().HasOne(bpf=>bpf.BlogPost)
.WithMany(bp=>bp.Features)
.HasForeignKey(bpf=>bpf.BlogPostId);
builder.Entity<BlogPostFeature>().HasOne(bpf=>bpf.Feature)
.WithMany(f=>f.BlogPosts)
.HasForeignKey(bpf=>bpf.FeatureId);

builder.Entity<BlogPostCategory>().HasKey(bpc=>new{bpc.BlogPostId,bpc.CategoryId});
builder.Entity<BlogPostCategory>().HasOne(bpc=>bpc.BlogPost)
.WithMany(bp=>bp.Categories)
.HasForeignKey(bpc=>bpc.BlogPostId);
builder.Entity<BlogPostCategory>().HasOne(bpc=>bpc.Category)
.WithMany(c=>c.BlogPosts)
.HasForeignKey(bpc=>bpc.CategoryId);
}

publicstaticasyncTaskCreateAuthorRole(IServiceProviderserviceProvider)
{
RoleManager<IdentityRole>roleManager=serviceProvider.GetRequiredService<RoleManager<IdentityRole>>
();

if(awaitroleManager.FindByNameAsync("Authors")==null)
{
IdentityResultresult=awaitroleManager.CreateAsync(newIdentityRole("Authors"));
if(!result.Succeeded)
{
thrownewException("Errorcreatingauthorsrole!");
}
}
}
publicstaticasyncTaskCreateAdminAccount(IServiceProviderserviceProvider,IConfiguration
configuration)
{
UserManager<ApplicationUser>userManager=
serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
RoleManager<IdentityRole>roleManager=serviceProvider.GetRequiredService<RoleManager<IdentityRole>>
();

stringuserName=configuration["Data:AdminUser:Name"];
stringemail=configuration["Data:AdminUser:Email"];
stringpassword=configuration["Data:Adminuser:Password"];
stringrole=configuration["Data:AdminUser:Role"];

if(awaituserManager.FindByNameAsync(userName)==null)
{
if(awaitroleManager.FindByNameAsync(role)==null)
{
awaitroleManager.CreateAsync(newIdentityRole(role));
}
ApplicationUseruser=newApplicationUser
{
UserName=userName,
Email=email
};
IdentityResultresult=awaituserManager.CreateAsync(user,password);
if(result.Succeeded)
{
awaituserManager.AddToRoleAsync(user,role);
}
}

https://www.codeproject.com/Articles/1178519/WritingaBlogEngineinASPNETCore?display=Print 6/12
3/28/2017 WritingaBlogEngineinASP.NETCoreCodeProject
}
}

This is, however, one of the spots that I ran into trouble with EF Core. That being with the manytomany relationships. The problem isn't
with defininig the relationship using the Fluent API. The documentation on the EF Core site for doing this is straight forward. The
problem was later on getting the queries to work smoothly the way that code on the internet said that it would. It's quite possible that
there is a bug in my code and that's the reason that it doesn't work as smoothly as it should. But in a case where I make use of the
manytomany relationship, such as finding the categories which are assigned to a particular blog post, I received null values back when
including categories. I was able to work around this with making two queries and doing it manually. So I might be doing something
wrong, but if you're using EF Core and having trouble with manytomany queries, you may want to look at the code that I have in a
method such as FeaturePosts within HomeController.cs as you can see below. There is a commented out line:

//varcategories=p.Categories.Select(c=>c.Category).ToList();

This is how most of the reference code suggested that I should be able to retrieve the data through the linking table, however I found
that I had to make a few queries in actuality because this was returning null values. Granted, it's hard to find an exact duplicate of the
query you're trying to make online on stack exchange or in someone else's blog all the time, so it's quite possible I just have to finesse it
somewhere a little bit to make it work correctly. But this is what I found so far. I've put the code for FeaturePosts below so you can see
what I'm talking about, and how I ended up crafting the queries to get access to the categories through the linking table.

//FeaturePostsfromHomeController.cs
publicasyncTask<IActionResult>FeaturePosts(longid)
{
varfeature=await_context.Features.FindAsync(id);

varbps=await_context.BlogPostFeature
.Where(bpf=>bpf.FeatureId==feature.Id&&bpf.BlogPost.Public==true&&
bpf.BlogPost.PublishOn<DateTime.Now)
.Select(bpf=>bpf.BlogPost)
.ToListAsync();

varposts=await_context.BlogPosts
.Include(bp=>bp.Author)
.Include(bp=>bp.Categories)
.Where(bp=>bps.Contains(bp))
.ToListAsync();

List<ViewBlogPostViewModel>viewPosts=newList<ViewBlogPostViewModel>();

foreach(varpinposts)
{
//varcategories=p.Categories.Select(c=>c.Category).ToList();

varcategoryIds=p.Categories.Select(c=>c.CategoryId);

varcategories=await(fromcatin_context.Categories
wherecategoryIds.Contains(cat.Id)
selectcat).ToListAsync();

varbpView=newViewBlogPostViewModel()
{
Author=$"{p.Author.FirstName}{p.Author.LastName}",
Title=p.Title,
Description=p.Description,
Categories=categories,
ModifiedAt=p.ModifiedAt,
Id=p.Id
};
viewPosts.Add(bpView);
}

ViewFeaturePostsViewModelvfpvm=newViewFeaturePostsViewModel()
{
Feature=feature,

https://www.codeproject.com/Articles/1178519/WritingaBlogEngineinASPNETCore?display=Print 7/12
3/28/2017 WritingaBlogEngineinASP.NETCoreCodeProject
BlogPosts=viewPosts
};

returnView(vfpvm);
}

I'll go over this code a litte in FeaturePosts. This is a controller action that returns the blog posts that correspond to the feature
passed in through the id parameter. There are actually two spots where I have to make an extra query to get data. The first query is
where I find the blog posts through the BlogPostFeature table. I was able to get the posts through this query, but when I tried to
include it's corresponding author and category in this query, that didn't work. So I had to make the next query directly from the
BlogPosts table, and here include the Author and Categories for the post.

But unfortunately even this didn't include everything in its results for the Categories, which is through the manytomany linking table. It
did return the results for the Author just fine, and I was able to access that below without making any other queries to retrieve that.

So I ended up having to get the Category Id's for each corresponding post, which were availble thankfully through the query above for
some reason it didn't link up the object correctly. After that I then had to query the Category table directoy to include the categories
which were present in the query above. You can see how I did this using the Contains method on the categoryIds list.

In the end I found this to be a workable solution, but it did lead to a number of extra queries, where if I'm correct I should have basically
been able to get everything I need by including the Author and Categories from my first query to BlogPostFeatures. I don't get
that much traffic and this was a small project so I didn't fret over it too much, but is one of the spots I'm working on and trying to
improve.

Update 3272017

So it turns out I was doing the querying incorrectly, and relying a little too much on Intellisense to guide me here. It turns out that it is
possible to get all the information that I needed without the extra queries. The correct way is to use Include, followed by ThenInclude two
times to get the categories through the linking table. I found this out some help from Microsoft's support on the Entity Framework Core
Issues page. The correct way to do this is:

publicasyncTask<iactionresult>FeaturePosts(longid)
{
varfeature=await_context.Features.FindAsync(id);

if(feature==null)
{
returnNotFound();
}

varbpfs=await_context.BlogPostFeature
.Where(bpf=>bpf.FeatureId==feature.Id&&bpf.BlogPost.Public==true&&
bpf.BlogPost.PublishOn<DateTime.Now)
.Include(bpf=>bpf.BlogPost)
.ThenInclude(bp=>bp.Author)
.Include(bpf=>bpf.BlogPost)
.ThenInclude(bp=>bp.BlogPostCategory)
.ThenInclude(bpc=>bpc.Category)
.ToListAsync();

List<ViewBlogPostViewModel>viewPosts=newList<ViewBlogPostViewModel>();

foreach(varbpfinbpfs)
{
varbpView=newViewBlogPostViewModel()
{
Author=$"{bpf.BlogPost.Author.FirstName}{bpf.BlogPost.Author.LastName}",
Title=bpf.BlogPost.Title,
Description=bpf.BlogPost.Description,
Categories=bpf.BlogPost.BlogPostCategory.Select(c=>c.Category).ToList(),
ModifiedAt=bpf.BlogPost.ModifiedAt,
Id=bpf.BlogPost.Id
};
viewPosts.Add(bpView);
}
https://www.codeproject.com/Articles/1178519/WritingaBlogEngineinASPNETCore?display=Print 8/12
3/28/2017 WritingaBlogEngineinASP.NETCoreCodeProject

ViewFeaturePostsViewModelvfpvm=newViewFeaturePostsViewModel()
{
Feature=feature,
BlogPosts=viewPosts
};

returnView(vfpvm);
}
</iactionresult>

Ultimately I found that EF Core seems to perform well enough though, and I have done some rudimentary load testing on this page and
others on my server which is running up on AWS. It was able to handle about 100 requests per second It's not on some super powerful
dedicated server on the database access pages, and didn't seem to crash and burn, which is more traffic than I'll probably get anyway,
so I think it's okay for the most part.

The View part of the MVC is basically all of my Razor pages. I have to say that this is my least favorite part of programming for the web,
although frameworks like Bootstrap have made it easier, and using Highlight.js I was able to plug in some really cool syntax highlighting
for code samples. So I think it looks okay for the most part. I was also able to put together an editor for authoring pages where you
write your post in markdown. This uses a little bit of Ajax for a preview feature which sends the markdown to a controller which parses
the markdown and returns HTML back to the page. This is probably the only spot in the web application where I used Ajax to
communicate from the client to the server, but getting it to work was suprisingly easy. I used a library called CommonMark.Net which is
avaiable as a Nuget package to implement this. It took all of one function call to make it work. The code is in the AuthorController and
the client side code is located in the EditPost.cshtml and AddEditPostPage.js file which does the actual Ajax.

I did find however once I got used to coding in Razor a little bit that it was easy to pull it all together and display things. I'm still working
on making it look a little bit better, but using Bootstrap made it fairly easy to give the blog a relatively nice look and feel. Using
Bootstrap's grid layout system also makes it so that the page displays very nicely on mobile devices, which was a real plus I find. I ended
up implementing one tag helper, which is a class that allows you to customize some of the HTML for an element that it matches up with.
The one that I made looks for a DIV element with a certain attribute set on it, and then sets its content to a message of passed down
through the ViewContext. You can see how this works and how to access the ViewContext from a tag helper in
TagHelpers/DivEditSaveUpdateTagHelper.cs.

So I haven't gone over the code that much directly, but if you want to look through the code and get a feel for how it all comes
together I would recommend starting with the file Startup.cs. This is the startup class that is specified in Program.cs to be used by the
the web host builder and contains the code which configures services and MVC for use and tells it how to respond to HTTP requests.
From there I would probably recommend running the blog through Visual Studio 2017, which is the version of Visual Studio the project
is setup for now.

If you want to run it the easiest way I found to do it while testing on my local system was to create a user that had create database
permissions on my workstation so that EF Core was able to create the database from scratch if I had to drop it because I messed
something up royally. After setting up the connection string you need to specify one using either appsettings.json, the user secrets
tools, or an environment varialbe You should be able to run:

dotnetefmigrationsaddinitial
dotnetefdatabaseupdate

And if you have the user setup correctly it should create the database for you based upon your connection string. This needs to be run
from the project folder on the command line for it to work. Before running the application you should change the settings in
appsettings.json for your own email address or a dummy address, otherwise you'll be using my email and password to log in. It
reads this file on application startup and creates a new admin user in the database if it isn't found there already ... I should
probably change that. If you want the full text search to work you need to create a full text index on the BlogPost table in the database.
This is as simple as right clicking on the table and following a short wizard from with SQL Server Management Studio. I used SQL Server
2016 Development Edition during the development and when I deployed it I ended up using the Express edition for licensing.

Summary
Well I learned a lot about ASP.NET Core MVC and how it comes together. I found that it was relatively straight forward to use, and that
even though it is a new product, there is a good deal of information for it online. I also found that for the most part Microsoft's
documentation for ASP.NET Core and EF Core is pretty good, although I wish they would go into more depth on EF Core. That project is
open source as well, and if you're used to using a version of EF besides EF Core, the learning curve probably won't be as steep. That
https://www.codeproject.com/Articles/1178519/WritingaBlogEngineinASPNETCore?display=Print 9/12
3/28/2017 WritingaBlogEngineinASP.NETCoreCodeProject

being said, I had not used LINQ much prior to starting this project, and I found that working with it and EF Core was pretty nice. I did
manage to actually run into a bug in EF Core and I was able to confirm it was a bug thanks to the fact that they have the issues on
Github, this was a relief so that I didn't spend too much time pulling my hair out over why something wasn't working. I still wish that the
manytomany relatinships worked a little bit better, and I get the feeling that if they did I would have been able to cut back on the
number of queries that I had to write in LINQ.

Using Identity for the authentication in the end I think made sense for my blog. I did ultimately find some other code online where you
can make use of some simple cookie authentication, but I had already started using Identity for the project and doing it that way didn't
have the ease of integrating Twitter authentication into the project. The code for using Identity is contained within the Account class
which handles logging in and out, and then the Admin class which has action methods for editing users. The messiest function I wrote is
definitely the one for editing a user, and I need to come back to that to clean it up and shorten it a bit if I can.

In retrospect I think I could have gotten away with using MySQL if I didn't go with Identity. The dependency on EF Core drove a lot of
the design on my app and ultimately my decision to go with SQL Server over MySQL. This was basically all due to using Identity and not
wanting to have to use two ORMs.

If you are going to start a web application and plan on using ASP.NET Core I think that overall it was a nice environment to develop
with. If you don't plan on using Identity for authentication I think that it would be easy to use another ORM, or just plain database
access to manage your data, or if you don't need a database then you don't have to worry about any of that. If you do plan on using
Identity then you are going to have to get your hands a little dirty with EF Core though. I think the template web application that
Microsoft provides comes setup to use Sqlite with it so that you don't really have to do much to get it working, but if you want another
database you will have to get a little comfortable with the one you choose. I'm fairly sure that if I messed with MySQL and the nuget
packages available a little bit more I may have been able to get it to work by scripting the migrations and applying the schema updates
using the scripts. There is also a way to go from an existing database model and have EF Core create your classes for you, but I haven't
played around with this at all so I can't comment on how that works.

The only part left over that I still need to master is handling the flow of EF Core going from the development database to the production
database. EF Core lets you output a SQL Script of the migrations that it applies which you can then run manually against a target
database,

I started off writing Bagombo becuase I didn't come across that many open source blogs for ASP.NET Core yet, and I decided that I
would just write my own. Overall there are a number of things that I plan on improving with it already, but it was a fun project, and it's
basically usable now. The next item on my list of things to add to it is pagination support, so that when a lot of blog entries are returned
it will be easier to page through them instead of having to scroll. This didn't make it in so far because I don't have that many blog
entries at all. I also plan on changing the links to the blog entries so that the link uses the title instead of the blog id, this may be better
for SEO as far as Google is concerned.

I also think that if I was to do it again I would just set it up so that there is a single user for the system. I'm guessing that most blogs are
just used by a single author, although for now, Bagombo let's you have as many authors as you want.

Thanks for taking the time to read this and if you're considering writing your own blog engine in ASP.NET Core either as a learning
exercise or to actually use I highly recommend trying it. I had basically zero experience with it before this and found that things really
came together pretty well. The trickiest part sometimes was getting the queries to work with EF Core, but even that wasn't too bad after
a while and as time passes there is more and more available online to see how to do it. Most of my queries are in the Home, Author, and
Admin controllers, so you can take a look at this code to see how I did it. If you see something that I missed or if theres a better way to
do it I'd love to hear from you. If you do make your own blog engine good luck, it's a fun project and there are a lot of different ways
you can do it.

License
This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author


https://www.codeproject.com/Articles/1178519/WritingaBlogEngineinASPNETCore?display=Print 10/12
3/28/2017 WritingaBlogEngineinASP.NETCoreCodeProject

Tyler Rhodes
Software Developer
United States

I've been programming and working with computers professionally for over 10 years now.

It all started as a hobby a long time ago when a friend introduced me to QBasic.

From there I've programmed in a lot of languages like C, C++, C#, Java, JavaScript and now a little bit of Go. I don't really have a
favorite, but if I had to pick I like C# right now.

I also have a long background of doing systems and network engineering and know about things like email and phone systems,
Active Directory and setting up VPNs.

You may also be interested in...


NoSQL Database Evaluation Guide Benchmark: MongoDB 3.2 vs. Couchbase Server
4.5 for Query and Read/Write Performance

sBlog.Net A Minimalistic Blog Engine Using Intel Advisor Review


ASP.NET MVC 3

YaBlogEngine A Tiny Blog Engine written in Equipment Activity Monitor in Python


ASP.NET/C#

Comments and Discussions


4 messages have been posted for this article Visit https://www.codeproject.com/Articles/1178519/WritingaBlogEnginein
ASPNETCore to post and view comments on this article, or click here to get a print view with messages.

Permalink | Advertise | Privacy | Terms of Use | Mobile Article Copyright 2017 by Tyler Rhodes
Select Language
Web02 | 2.8.170308.1 | Last Updated 28 Mar 2017 Everything else Copyright CodeProject, 19992017

https://www.codeproject.com/Articles/1178519/WritingaBlogEngineinASPNETCore?display=Print 11/12
3/28/2017 WritingaBlogEngineinASP.NETCoreCodeProject

https://www.codeproject.com/Articles/1178519/WritingaBlogEngineinASPNETCore?display=Print 12/12

You might also like