gothinkster / aspnetcore-realworld-example-app Goto Github PK
View Code? Open in Web Editor NEWASP.NET Core backend implementation for RealWorld
Home Page: https://realworld.io
License: MIT License
ASP.NET Core backend implementation for RealWorld
Home Page: https://realworld.io
License: MIT License
There are cases (like in Create/Edit Article commands that multiple calls to SaveChanges are made inside the command). If the second SaveChanges call fails for some reason, the data saved by the first SaveChanges call does not get rolled back, leading to database inconsistencies.
It would be nice to implement a transaction per HTTP API call (as a filter added to the ASP NET core pipeline).
It appears that exception.Message
is sent back to the user for any Exception. Should this be replaced with a constant message?
If not setting the environment variables, the default connection is hard-coded to SQLite as it prefixed with a "Filename="
var connectionString = _config.GetValue<string>("ASPNETCORE_Conduit_ConnectionString") ?? $"Filename={DEFAULT_DATABASE_FILE}";
Also to make it consistent, the default variable should be named "connection string" like the environment variable.
Is there a reason that something like Create.cs has Create as a class instead of a namespace? I have also been frequently told that I should follow one class per file. Would it be better to have create be a folder with The command/validator/handler as classes inside of that folder?
how to upgrade .net core 2.0 ?
the project is not compiled.
I must have done something differently because someone would have raised a concern before this, but I could not get _httpContextAccessor.HttpContext.User?.Claims?.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)?.Value;
in CurrentUserAccessor
to return a value. In fact, User.Claims was always empty.
I fixed the problem by adding app.UseAuthentication();
above app.UseMvc();
in Startup.cs
, but I thought I'd mention this in case I did something wrong. How are others getting the claims to appear without this line?
It looks as though the existing System.Text.Json serialisation library is having problems trying to serialise the Article object graph upon trying to create a new article:
System.Text.Json.JsonException: A possible object cycle was detected which is not supported.
I've been able to fix this on my local (Ubuntu) setup by using the Newtonsoft library instead. If there's an appetite to go after this fix I can create a PR with my changes later this evening?
I forgot to fix Circle when this repo got migrated to this location.
Add caching on both db and http levels.
I see one requires the CurrentUserAcessor, is the only reason for /user vs /users is that one requires authentication?
When I try to delete an article which has comments, I get the following exception:
{Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> Microsoft.Data.Sqlite.SqliteException: SQLite Error 19: 'FOREIGN KEY constraint failed'. at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db) at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior) at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteAsync(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary2 parameterValues, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken) --- End of inner exception stack trace --- at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(DbContext _, ValueTuple
2 parameters, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IReadOnlyList1 entriesToSave, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken) at Conduit.Features.Articles.Delete.QueryHandler.Handle(Command message, CancellationToken cancellationToken) in C:\Sergiu\Net\DotNet\Realworld\aspnetcore-realworld-example-app\src\Conduit\Features\Articles\Delete.cs:line 52 at Conduit.Infrastructure.ValidationPipelineBehavior
2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate1 next) in C:\Sergiu\Net\DotNet\Realworld\aspnetcore-realworld-example-app\src\Conduit\Infrastructure\ValidationPipelineBehavior.cs:line 33 at Conduit.Features.Articles.ArticlesController.Delete(String slug) in C:\Sergiu\Net\DotNet\Realworld\aspnetcore-realworld-example-app\src\Conduit\Features\Articles\ArticlesController.cs:line 59 at lambda_method(Closure , Object ) at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult() at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.AwaitableResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at System.Threading.Tasks.ValueTask
1.get_Result() at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync() at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync() at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync() at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.Invoke(HttpContext context) at Conduit.Infrastructure.Errors.ErrorHandlingMiddleware.Invoke(HttpContext context) in C:\Sergiu\Net\DotNet\Realworld\aspnetcore-realworld-example-app\src\Conduit\Infrastructure\Errors\ErrorHandlingMiddleware.cs:line 31} | System.Exception {Microsoft.EntityFrameworkCore.DbUpdateException}
This is because the data model for table Comment defines the foreign keys as ON DELETE RESTRICT instead of ON DELETE CASCADE.
Hi @adamhathcock ,
When we run the following command on Windows 10 We are getting the below error.
C:\Users\sachin\Downloads\aspnetcore-realworld-example-app-master\publish>dotnet Conduit.dll
A fatal error was encountered. The library 'hostpolicy.dll' required to execute the application was not found in 'C:\Users\sachin\Downloads\aspnetcore-realworld-example-app-master\publish'.
Steps taken
Thanks
Don't know if this is a bug or a configuration:
To reproduce:
git clone ...
open vs and then the sln file
In the startup file, change default to connect to local database
public const string DEFAULT_DATABASE_CONNECTIONSTRING = "Data Source=********;Initial Catalog=Conduit;Persist Security Info=True;User ID=conduit;Password=";
and
public const string DEFAULT_DATABASE_PROVIDER = "sqlserver";
start debugging (hitting f5):
In the browser:
Receive 404, also when calling 127.0.0.0:44460: host rejected connection.
In the output it says:
Conduit> Now listening on: http://127.0.0.1:44460
and later, after calling anything:
Conduit> 14:39:36 [Information] Microsoft.AspNetCore.Hosting.Internal.WebHost Request starting HTTP/1.1 GET http://localhost:56055/api/tags
Conduit> 14:39:36 [Information] Microsoft.AspNetCore.Hosting.Internal.WebHost Request finished in 0.467ms 404
Thanks in advance, I love this project
I am not sure if that app is the best real-world example of a ASP.NET Core app.
Microsoft states that this pattern isn't recommended in situations where the domain or the business rules are simple, a simple CRUD-style user interface and the related data access operations are sufficient and/or for implementation across the whole system.
There are specific components of an overall data management scenario where CQRS can be useful, but it can add considerable and unnecessary complexity when it isn't required."
Hi
First, thanks for creating a full production application, it is a great starting point! I do have a problem:
Conditions:
I cloned the front end, made some cosmetic changes to it, still using the production server for back end, all works fine, I can log in, log out, create articles see the articles.
I cloned this one front end, asp.net core, no changes whatsoever, ran it, change the UI side environment to point to it, then I can register, log in, see the settings, log out, no problem.
Problem:
When I try to create an article, I get a 401 status code, with no more explanation on the response.
Request:
curl 'http://localhost:5000/articles/' -H 'Pragma: no-cache' -H 'Origin: http://localhost:4200' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-US,en;q=0.9' -H 'Authorization: Token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJrYWx2YXJlejJAZ21haWwuY29tIiwianRpIjoiNzI0OTRkMTAtNGU0Yy00MzYwLWI1MGItNDMwMDMxYTEyMDgwIiwiaWF0IjoxNTI5NjA4OTg5LCJuYmYiOjE1Mjk2MDg5ODksImV4cCI6MTUyOTYwOTI4OSwiaXNzIjoiaXNzdWVyIiwiYXVkIjoiYXVkaWVuY2UifQ.IRmitcvS_CD9bo9kXwrO3gmQMUAS2aYTgaJpCqbESeE' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Cache-Control: no-cache' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36' -H 'Connection: keep-alive' -H 'Referer: http://localhost:4200/editor' --data-binary '{"article":{"tagList":[],"title":"aaaa","description":"aaaaaaaaaaaaaaa","body":"aaaaaaaaaa"}}' --compressed
Server Log:
15:23:32 [Information] Microsoft.AspNetCore.Hosting.Internal.WebHost Request starting HTTP/1.1 OPTIONS http://localhost:5000/articles/
15:23:32 [Information] Microsoft.AspNetCore.Cors.Infrastructure.CorsService Policy execution successful.
15:23:32 [Information] Microsoft.AspNetCore.Hosting.Internal.WebHost Request finished in 0.3615ms 204
15:23:32 [Information] Microsoft.AspNetCore.Hosting.Internal.WebHost Request starting HTTP/1.1 POST http://localhost:5000/articles/ application/json 93
15:23:32 [Information] Microsoft.AspNetCore.Cors.Infrastructure.CorsService Policy execution successful.
15:23:32 [Information] Microsoft.AspNetCore.Authorization.DefaultAuthorizationService Authorization failed for user: null.
15:23:32 [Information] Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker Authorization failed for the request at filter '"Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter"'.
15:23:32 [Information] Microsoft.AspNetCore.Mvc.ChallengeResult Executing ChallengeResult with authentication schemes (["Token", "Bearer"]).
15:23:32 [Information] Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler AuthenticationScheme: "Token" was challenged.
15:23:32 [Information] Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler AuthenticationScheme: "Bearer" was challenged.
15:23:32 [Information] Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker Executed action "Conduit.Features.Articles.ArticlesController.Create (Conduit)" in 0.7429ms
15:23:32 [Information] Microsoft.AspNetCore.Hosting.Internal.WebHost Request finished in 4.3307ms 401
Hello,
I am reading my way through the code and am curious about business logic and unit tests, I see there is an integration test project.
Is business logic supposed to go right in the command handler? Would a larger app separate out the logic from the database code inside the handler?
I'm building a new asp.net web api using .net core 2.1.
To begin with I used NuGet packages of 2.1.1 and I ran into dependency issues.
I now seem to have a stable project that uses 2.1.0-preview1-final.
The NuGet gallery website allows different versions to be used but which version is best ?
What is the best practice surrounding this ?
Are OPTIONS action needed for CORS pre-flight requests?
/// <summary>
/// Returns an Allow HTTP header with the allowed HTTP methods.
/// </summary>
/// <returns>A 200 OK response.</returns>
[HttpOptions]
[SwaggerResponse(StatusCodes.Status200OK, "The allowed HTTP methods.")]
public IActionResult Options()
{
this.HttpContext.Response.Headers.AppendCommaSeparatedValues(
HeaderNames.Allow,
HttpMethods.Get,
HttpMethods.Head,
HttpMethods.Options,
HttpMethods.Post);
return this.Ok();
}
/// <summary>
/// Returns an Allow HTTP header with the allowed HTTP methods for a car with the specified unique identifier.
/// </summary>
/// <param name="carId">The cars unique identifier.</param>
/// <returns>A 200 OK response.</returns>
[HttpOptions("{carId}")]
[SwaggerResponse(StatusCodes.Status200OK, "The allowed HTTP methods.")]
public IActionResult Options(int carId)
{
this.HttpContext.Response.Headers.AppendCommaSeparatedValues(
HeaderNames.Allow,
HttpMethods.Delete,
HttpMethods.Get,
HttpMethods.Head,
HttpMethods.Options,
HttpMethods.Patch,
HttpMethods.Post,
HttpMethods.Put);
return this.Ok();
}
I have upgraded all NuGet and SDK packages to the 2.1.1 version following advice not to use the preview versions, but now IApplicationBuilder has red squiglly line and is not recognised in Startup.cs:
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
......
Also WebHost in Program.cs isn't recognised either
I think that there should be a lot more comments in the code of certain projects. For example, the ASP.NET Core project just says "We based this on someones project" and then never explains chunks of code like this.
The tag, author, favorited query params should not be required according to @gothinkster/realworld API swagger documentation:
https://github.com/gothinkster/realworld/blob/ae9939d5356739cfaa8486e403520d69ef370806/api/swagger.json#L361
https://github.com/gothinkster/realworld/blob/ae9939d5356739cfaa8486e403520d69ef370806/api/swagger.json#L368
https://github.com/gothinkster/realworld/blob/ae9939d5356739cfaa8486e403520d69ef370806/api/swagger.json#L375
Same goes for GET /articles/feedpagination params.
Pagination params should also be optional.
I'm playing around and am curious how one would pass creds or a token in an integration test? Would it be more appropriate to do so in a test that invokes a authorized controller and goes through the traditional request pipeline? Is there a way I can pass along a user's context when testing specific commands and/or queries outside of that pipeline?
Add an appropriate reaction to cancelled/aborted requests with CancellationToken
.
Not sure, just glancing through the code, but in user Edit it doesn't seem like user names are required to be unique when editing? all the code to deal with uniqueness is on create.
A current user could change their username to another users user name,
Then they could edit again and then the firstordefault will likely give them access to the original user.
I'm using this backend together with the vue frontend and upon refreshing the page the token seems to be cleared and the /user endpoint returns a 401. Doesn't seem to happen on https://conduit.productionready.io/api.
Found out that documentation is not updated with the corresponding 'Makefile'.
'make run' command does not execute 'docker-compose run' it actually runs 'docker-compose up'
I have created a pull request for this.
Why Envelope return Domain object?
Is bad practices
I noticed that all the validators run as expected during Model Binding (probably because of .AddFluentValidation(cfg => { cfg.RegisterValidatorsFromAssemblyContaining<Startup>(); });
) and they never even have a chance to make it to the ValidationPipelineBehavior
. I assume that is why we just throw in there because something is very wrong if we got that far.
Why even have this? Just as a safety net or are there situations where this comes in handy?
Hi,
it would be nice if the database provider / connection string is read from a configuration file and not hard-code to SqlLite (in Startup and ConduitContext).)
I can imagine that someone would like to use an InMemoryDatabase for testing.
Greetings,
Sergiu
Hello can you add asp core frontend
If you try to add a tag when editing an article, and that tag has already been used in one or more articles, a database error occurs because it is trying to insert a duplicate into the Tags table:
SQLite Error 19: 'UNIQUE constraint failed: Tags.TagId'.
What is the purpose of an Envelope? Is it just a DTO? Why not return Comments directly?
https://github.com/gothinkster/aspnetcore-realworld-example-app/blob/master/.dockerignore
This file doesn't have the .git
folder in it but I think you would normally want to ignore that. Is that true?
Hey there!
Thank you for this and other "realworld-example" series of apps.
It really helps me to discover how it may works on production.
I'm trying to build the application as it says in README.MD via docker build but I got an issues.
make build
WARN[0000] The "ASPNETCORE_Conduit_DatabaseProvider" variable is not set. Defaulting to a blank string. WARN[0000] The "ASPNETCORE_Conduit_ConnectionString" variable is not set. Defaulting to a blank string. [+] Building 0.4s (7/7) FINISHED docker:desktop-linux => [conduit internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 688B 0.0s => [conduit internal] load .dockerignore 0.0s => => transferring context: 4.78kB 0.0s => [conduit internal] load metadata for mcr.microsoft.com/dotnet/runtime:7.0 0.4s => [conduit base 1/2] FROM mcr.microsoft.com/dotnet/runtime:7.0@sha256:b41a241da8624e65544dd83cbcc642152f10a751082d1ea1a912e2 0.0s => CACHED [conduit base 2/2] WORKDIR /app 0.0s => CACHED [conduit final 1/1] WORKDIR /app 0.0s => [conduit] exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:80d386cc567b8f19e4459f47196377f8bad107e2398677dd621e3344510e0152 0.0s => => naming to docker.io/library/aspnetcore-realworld-example-app-conduit 0.0s
What does actually do this variables? Should I need put something to it?
make run
WARN[0000] The "ASPNETCORE_Conduit_DatabaseProvider" variable is not set. Defaulting to a blank string. WARN[0000] The "ASPNETCORE_Conduit_ConnectionString" variable is not set. Defaulting to a blank string. [+] Building 0.0s (0/0) docker:desktop-linux [+] Running 1/0 ✔ Container aspnetcore-realworld-example-app-conduit-1 Created 0.0s Attaching to aspnetcore-realworld-example-app-conduit-1 aspnetcore-realworld-example-app-conduit-1 | The command could not be loaded, possibly because: aspnetcore-realworld-example-app-conduit-1 | * You intended to execute a .NET application: aspnetcore-realworld-example-app-conduit-1 | The application 'Conduit.dll' does not exist. aspnetcore-realworld-example-app-conduit-1 | * You intended to execute a .NET SDK command: aspnetcore-realworld-example-app-conduit-1 | No .NET SDKs were found. aspnetcore-realworld-example-app-conduit-1 | aspnetcore-realworld-example-app-conduit-1 | Download a .NET SDK: aspnetcore-realworld-example-app-conduit-1 | https://aka.ms/dotnet/download aspnetcore-realworld-example-app-conduit-1 | aspnetcore-realworld-example-app-conduit-1 | Learn about SDK resolution: aspnetcore-realworld-example-app-conduit-1 | https://aka.ms/dotnet/sdk-not-found aspnetcore-realworld-example-app-conduit-1 exited with code 145
As you can be seen from error "You intended to execute a .NET application: The application 'Conduit.dll' does not exist." and "You intended to execute a .NET SDK command: No .NET SDKs were found."
Add a graceful shutdown on app stop/restart.
Taking a look at your repository it doesn't seem like you have a license. Was that intentional? If not, would you be able to add one?
Whats the motivation for this?
First up - great project - I really like the way features co-habitate a smaller part of the project than usual - I'm sure it leads to cleaner PR's too.
I cant figure this out though.. There are Fluent Validators applied to queries in a few places.
public class QueryValidator : AbstractValidator<Query>
{
public QueryValidator()
{
RuleFor(x => x.Username).NotNull().NotEmpty();
}
}
But the Query classes are instantiated manually in the controllers which I believe means that the validation isn't ever being executed.
// eg
[HttpGet("{username}")]
public async Task<ProfileEnvelope> Get(string username)
{
return await _mediator.Send(new Profiles.Details.Query() { Username = username });
}
// and
[HttpGet("{slug}")]
public async Task<ArticleEnvelope> Get(string slug)
{
return await _mediator.Send(new Details.Query(slug));
}
The pattern works well with the commands which are bound as part of MVC's request pipeline and have their validation performed before even entering the action..
public async Task<CommentEnvelope> Create(string slug, [FromBody]Create.Command command)
{
command.Slug = slug;
return await _mediator.Send(command);
}
presumably because of this registration
.AddMvc(opt => ......
.AddFluentValidation(cfg => { cfg.RegisterValidatorsFromAssemblyContaining<Startup>(); });
Am i missing something? Is Mediatr meant to be executing those validators?
Should the handler be aware of HTTP/"Rest"? I might argue that the controller should try and retrieve the entity and then throw NotFound()
;
Cloned this project and the React / Redux client project, ran both but when posting an article it gives the error message:
No authentication handler is configured to authenticate for the scheme: Token
Should be able to update tags when an article is updated.
Any plans to add compression middle-ware? Any specific reason it is not already here?
Hi,
I tried to debug/run this project using VS 2022 and VS Code and I got the following error in Chrome:
This localhost page can’t be found No webpage was found for the web address: https://localhost:5001/
HTTP ERROR 404
Any help will be much appreciated.
TIA
I mentioned this in my PR (#14), but after the recent change of ValidationPipelineBehavior, after logging in and viewing the homepage which grabs the Tags List, this error is returned:
Unable to resolve service for type 'FluentValidation.IValidator1[Conduit.Features.Tags.List+Query]' while attempting to activate Conduit.Infrastructure.ValidationPipelineBehavior2[Conduit.Features.Tags.List+Query,Conduit.Features.Tags.TagsEnvelope]'.
I noticed a bunch of code was changed and my localizer is no longer in use. What happened with the merge here? Where did this all come from?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.