Giter Site home page Giter Site logo

dotnet-presentations / aspnetcore-app-workshop Goto Github PK

View Code? Open in Web Editor NEW
665.0 51.0 368.0 8.65 MB

This workshop will teach you ASP.NET Core by building a complete conference management website from scratch.

License: MIT License

C# 82.17% CSS 0.96% JavaScript 0.36% TypeScript 1.64% HTML 14.00% Dockerfile 0.79% Mustache 0.06%
aspnet-core dotnet-core workshop

aspnetcore-app-workshop's Introduction

ASP.NET Core - App Building Workshop

Build Status

BackEnd Web API | FrontEnd Web App

Setup

Download and install the .NET Core SDK and Visual Studio.

Note: When installing Visual Studio you only need to install the ASP.NET and web development workload.

If you have issues downloading the installers we may have USB sticks with offline installers for you to use.

What you'll be building

In this workshop, you'll learn by building a full-featured ASP.NET Core application from scratch. We'll start from File/ New and build up to an API back-end application, a web front-end application, and a common library for shared data transfer objects using .NET Standard.

Application Architecture

Architecture Diagram

Database Schema

Database Schema Diagram

Sessions

Session Topics
Session #1 Build the back-end API with basic EF model
Session #2 Finish the back-end API and EF model, refactor into view models
Session #3 Add front-end, render agenda, set up front-end models
Session #4 Add authentication, add admin policy, allow editing sessions, users can sign-in with Identity, custom auth tag helper
Session #5 Add user association and personal agenda
Session #6 Deployment, Azure and other production environments, configuring environments, diagnostics
Session #7 Challenges
Session #8 SPA front-end

aspnetcore-app-workshop's People

Contributors

andriysvyryd avatar bitbonk avatar bradygaster avatar coolcsh avatar csharpfritz avatar damianedwards avatar danroth27 avatar davidfowl avatar dependabot[bot] avatar dnfadmin avatar haacked avatar jongalloway avatar leonyu1010 avatar maximilianast avatar michael-wolfenden avatar mikaelm12 avatar mvanwieringen avatar natemcmaster avatar nje avatar petermarcu avatar pranavkm avatar rblackman avatar scottsauber avatar seankilleen avatar shanselman avatar spboyer avatar therubble avatar truongminh avatar vnvizitiu avatar willdean avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aspnetcore-app-workshop's Issues

Need to update to 2.1

If you only have Visual Studio 2017 installed fresh (newbie) and have not installed SDK 2.0, solution will not load.

Frontend URL returns 500

When attempting to see Frontend Web Page, you get a HttpRequestException: Response status code does not indicate success: 500 (Internal Server Error).

Suggestion: Large code + extract file for longer examples

For those examples that involve a number of copy/pasting several new files' worth of code, might make sense to have folks copy/paste into a BigCopiedFile.cs or something similar and then utilize shortcuts to extract those classes to individual files. I think VS & ReSharper both have shortcuts for this though I'm not sure the VS / VSCode ones off-hand.

If you like this idea, I can submit a PR to combine some of the examples that run one after the other.

What is this initialized yet mutable collection property for?

I found a suspicious property quoted from the repository as follows.

public class Speaker : ConferenceDTO.Speaker
{
    public virtual ICollection<SessionSpeaker> SessionSpeakers { get; set; } = new List<SessionSpeaker>();
}

Question

I don't understand why the initialized collection is made mutable?

Missing steps from Session 5

  • UserSessions property is missing from the Index page model
  • Missing page handler for adding and removing sessions to personal agenda

Add unit tests with mocking of ef

I would love to see some unit tests around this code as a new user to EF having used other ORM's for years. It is not obvious how you would mock and test the concrete classes for the dbcontext and the dbsets.

SQL Server via Docker

For Linux/macOS users or Windows users without Visual Studio, it's actually failry trivial to use SQL Server instead of SQLite if they have Docker installed:

docker run -e ACCEPT_EULA=Y -e SA_PASSWORD=Password12! -p 1433:1433 -d mcr.microsoft.com/mssql/server

Use this conneciton string:

"DefaultConnection": "User ID=sa;Password=Password12!;Database=ConferencePlanner"

Session 1 : Elaborate steps for Visual Studio with diagrams

  1. In the initial instruction of Session 1, while clear steps have been enunciated for command line, the Visual Studio code has been left to the discretion of workshop participant.

  2. In VS, perhaps we can give a name to the solution. But more importantly we need to mention that VS Project created should be named 'Backend'. This step is only made explicit for the cmdline users.

image

Scaffolding as described in the section "Create BackEnd API project" ends with error

I have tried the first section "Create BackEnd API project". However, when I scaffold the API controller using Visual Studio, it fails with the following error:

Method 'Create' in type 'Microsoft.EntityFramework.Core.SqlServer.Query.Internal.SqlServerTranslatingExpressionVisitorFactory' ... does not have implementation.

aspnetworkshoperror

I have tried to solve this by updating all nugets. However, there is problem with Microsoft.VisualStudio.Web.CodeGeneration.Design (5.0.2). The latest version is not compatible wit .NET Core 3.1. So I tried to uninstall the package and install version 3.1.5 instead. The scaffolding still does not work. This time, it fails with error:

aspnetworkshoperror2

I do not know if the problem is with the instructions in this workshop, in some of the Nuget packages, or in the scaffolding in Visual Studio. Maybe specific versions of Nugets are required. It is sad when such basic things does not work out of the box. I have tried scaffolding for API controllers in .NET framework and some older versions of .NET Core and it worked without problems that time.

I am using Visual Studio 2019 (version 16.9.4).

EditSession page should provide better experience for editing start and end time

This is the current experience for editing the start/end time on the EditSession page:

image

It currently relies on the default input field rendering for DateTimeOffset which isn't great, due to issues with the browsers' own pickers not supporting round-trippable formats.

We might have to split the date/time and time-zone offset info into their own input fields with the date/time portion being one, and a time-zone picker being the other, e.g.:

<input name="StartTime.DateTime" type="datetime-local" />
<select name="StartTime.Offset"> ...

Conflicting schemaIds at the end of session 2

I've been following the steps and at the end of Session 2, when I run the app and go the "/swagger" url I get an exception about "Conflicting schemaIds".

It's just me?

I fixed it by adding this to the swagger configuration in the startup.cs:
options.CustomSchemaIds(x => x.FullName);

Exception details:

System.InvalidOperationException: Conflicting schemaIds: Identical schemaIds detected for types BackEnd.Data.Speaker and ConferenceDTO.Speaker. See config settings - "CustomSchemaIds" for a workaround at Swashbuckle.AspNetCore.SwaggerGen.SchemaIdManager.IdFor(Type type) at Swashbuckle.AspNetCore.SwaggerGen.SchemaRegistry.CreateReferenceSchema(Type type, Queue1 referencedTypes)
at Swashbuckle.AspNetCore.SwaggerGen.SchemaRegistry.GetOrRegister(Type type)
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.CreateBodyParameter(ApiParameterDescription apiParameterDescription, String name, Boolean isRequired, ISchemaRegistry schemaRegistry)
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.CreateParameter(ApiDescription apiDescription, ApiParameterDescription apiParameterDescription, ISchemaRegistry schemaRegistry)
at System.Linq.Enumerable.WhereSelectListIterator2.ToList() at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source)
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.CreateOperation(ApiDescription apiDescription, ISchemaRegistry schemaRegistry)
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.CreatePathItem(IEnumerable1 apiDescriptions, ISchemaRegistry schemaRegistry) at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable1 source, Func2 keySelector, Func2 elementSelector, IEqualityComparer1 comparer) at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.CreatePathItems(IEnumerable1 apiDescriptions, ISchemaRegistry schemaRegistry)
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GetSwagger(String documentName, String host, String basePath, String[] schemes)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContextOfT1.ProcessRequestAsync()

After clone this repo, dotnet dev-certs is required to solve AuthenticationException

I changed my job a year ago and that fact made me move away from asp.net development. I am trying to catch up asp.net core using this app. However, when I run this app after repo, I met the following error

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
   at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Security.SslState.ThrowIfExceptional()
   at System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslState.EndProcessAuthentication(IAsyncResult result)
   at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
   at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__47_1(IAsyncResult iar)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask`1 creationTask)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at FrontEnd.Services.ApiClient.GetSessionsAsync() in /Users/shootingstar/Code/booksource/aspnetcore-app-workshop/src/FrontEnd/Services/ApiClient.cs:line 69
   at FrontEnd.Services.ApiClient.GetSessionsByAttendeeAsync(String name) in /Users/shootingstar/Code/booksource/aspnetcore-app-workshop/src/FrontEnd/Services/ApiClient.cs:line 153
   at FrontEnd.Pages.IndexModel.OnGetAsync(Int32 day) in /Users/shootingstar/Code/booksource/aspnetcore-app-workshop/src/FrontEnd/Pages/Index.cshtml.cs:line 43
   at Microsoft.AspNetCore.Mvc.RazorPages.Internal.ExecutorFactory.NonGenericTaskHandlerMethod.Execute(Object receiver, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.InvokeHandlerMethodAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.InvokeNextPageFilterAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.Rethrow(PageHandlerExecutedContext context)
   at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.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.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

After a few search, I found the following site
https://www.hanselman.com/blog/DevelopingLocallyWithASPNETCoreUnderHTTPSSSLAndSelfSignedCerts.aspx

and I could fix with this command dotnet dev-certs https --trust

I think it can be helpful if this potential issue is mentioned somewhere in a doco.

Instruction in the section "Generate the Entity Framework migration for our Identity schema" are not complete

I have run into problems when I was trying to add migration for Identity framework in the 4th part of this workshop (https://github.com/dotnet-presentations/aspnetcore-app-workshop/blob/master/docs/4.%20Add%20auth%20features.md).

When I run command Add-Migration CreateIdentitySchema, the created migration file is wrong. The metods Down() and Up() are empty in it. After spending some time by Googling, I have found out that the instructions in this workshop are missing an important detail - it is necessary to select "FrontEnd" in the Default project drop-down in the Package Manager Console. Without it, BackEnd project is selected and the migration file is empty. I recommend adding this at the end of the first step.

I also recommend adding step 3 that after generating the migration and updating the database, it is necessary to go to the solutions properties and select both FrontEnd and BackEnd as startup projects again.

Issue with CodeGenerator: error specifying that 2.1.5 is required?

Adding this here to surface it in case it can bubble its way up to the right spot; feel free to close if there's nowhere for this to go.

In the first section of the course, it references using the codegenerator to scaffold a controller:

dotnet aspnet-codegenerator controller -api -name SpeakersController -m Speaker -dc BackEnd.Models.ApplicationDbContext -outDir Controllers

However, no matter what framework I specify, when I run this command, I see:

The specified framework 'Microsoft.NETCore.App', version '2.1.5' was not found.

I don't yet have 2.1.5 but I expected this would be able to work on 2.1.x`.

dotnet --list-sdks:

  • 2.0.3 [C:\Program Files\dotnet\sdk]
  • 2.1.4 [C:\Program Files\dotnet\sdk]
  • 2.1.202 [C:\Program Files\dotnet\sdk]
  • 2.1.302 [C:\Program Files\dotnet\sdk]

dotnet --list-runtimes:

  • Microsoft.AspNetCore.All 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  • Microsoft.AspNetCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  • Microsoft.NETCore.App 2.0.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  • Microsoft.NETCore.App 2.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  • Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  • Microsoft.NETCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

Update session card Add/Remove buttons to use JavaScript

During the workshop today I added the ability for the session cards on the Home and My Agenda pages to progressively enhance the buttons for adding/removing sessions from the personal agenda to post using JavaScript rather than a normal form submit. It also handles dynamically updating the UI including removing the cards on the My Agenda page.

The JavaScript and modified agenda partial follow. We should consider incorporating this into the workshop.

site.js

"use strict";

// Agenda form functionality
let onMyAgendaPage = document.querySelector("h1[data-myAgenda]") !== null;
let form = document.querySelector("#agendaForm");
if (form) {
    form.addEventListener("submit", async e => {
        e.preventDefault();
        let sessionId = document.activeElement.getAttribute("value"),
            card = document.querySelector("#session-" + sessionId),
            button = card.querySelector("button:not(.template)"),
            template = card.querySelector("button.template"),
            url = button.formAction || form.action,
            formData = new FormData(form);

        formData.append("sessionId", sessionId);

        let response = await fetch(url, {
            method: form.method,
            body: formData
        });

        if (response.status === 200) {
            if (url.indexOf("Remove") > 0 && onMyAgendaPage) {
                let timeSlotDiv = card.closest("div.timeSlot"),
                    agendaDiv = document.querySelector("div.agenda"),
                    dayPill = agendaDiv.querySelector("a.nav-link.active");

                card.remove();

                // Check if this was the last card in this time slot and if so remove the track node
                if (timeSlotDiv.querySelectorAll(".session-card").length === 0) {
                    timeSlotDiv.remove();
                    // Check if this was the last card in the day and if so remove the day pill button
                    if (agendaDiv.querySelectorAll(".session-card").length === 0) {
                        dayPill.remove();
                        // Check if there are more days and if so navigate to the next day, else show the empty message
                        let dayPills = agendaDiv.querySelectorAll("a.nav-link");
                        if (dayPills.length > 0) {
                            document.location.search = "";
                        }
                        else {
                            agendaDiv.querySelector("#agendaMessage").classList.remove("template");
                        }
                    }
                }
            } else {
                button.classList.add("template");
                template.classList.remove("template");
            }            
        }
    });
}

_AgendaPartial.cshtml

@model IndexModel

<div class="agenda">
    <ul class="nav nav-pills mb-3">
        @foreach (var day in Model.DayOffsets)
        {
            <li role="presentation" class="nav-item">
                <a class="nav-link @(Model.CurrentDayOffset == day.Offset ? "active" : null)" asp-route-day="@day.Offset">@day.DayofWeek?.ToString()</a>
            </li>
        }
    </ul>

    @{
        var messageClassName = Model.Sessions.Any() ? "template" : null;
    }
    <p id="agendaMessage" class="@messageClassName">There don't appear to be any sessions here.</p>

    <form authz method="post" id="agendaForm">
        @foreach (var timeSlot in Model.Sessions)
        {
            <div class="timeSlot">
                <h4>@timeSlot.Key?.ToString("HH:mm")</h4>
                <div class="row">
                    @foreach (var session in timeSlot)
                    {
                        <div class="col-md-3 mb-4 session-card" id="[email protected]">
                            <div class="card shadow session h-100">
                                <div class="card-header">@session.Track?.Name</div>
                                <div class="card-body">
                                    <h5 class="card-title"><a asp-page="Session" asp-route-id="@session.Id">@session.Title</a></h5>
                                </div>
                                <div class="card-footer">
                                    <ul class="list-inline mb-0">
                                        @foreach (var speaker in session.Speakers)
                                        {
                                            <li class="list-inline-item">
                                                <a asp-page="Speaker" asp-route-id="@speaker.Id">@speaker.Name</a>
                                            </li>
                                        }
                                    </ul>
                                    <p class="mb-0">
                                        <a authz-policy="Admin" asp-page="/Admin/EditSession" asp-route-id="@session.Id" class="btn btn-default btn-xs">Edit</a>
                                        @{
                                            var isInSession = Model.UserSessions.Contains(session.Id);
                                            var removeClassName = isInSession ? "" : "template";
                                            var addClassName = isInSession ? "template" : "";
                                        }
                                        <button type="submit" name="sessionId" value="@session.Id" asp-page-handler="Remove" class="btn btn-default btn-sm bg-transparent @removeClassName" title="Remove from my personal agenda">
                                            <i class="icon ion-md-star" aria-hidden="true"></i>
                                        </button>
                                        <button type="submit" name="sessionId" value="@session.Id" class="btn btn-default btn-sm bg-transparent @addClassName" title="Add to my personal agenda">
                                            <i class="icon ion-md-star-outline" aria-hidden="true"></i>
                                        </button>
                                    </p>
                                </div>
                            </div>
                        </div>
                    }
                </div>
            </div>
        }
    </form>
</div>

ArgumentNullException: Value cannot be null. Parameter name: uriString

When I run the FrontEnd project in stage 3 I get the above error for "serviceUrl". The BackEnd project runs as expected. Here is my stacktrace:

System.Uri..ctor(string uriString)
FrontEnd.Startup.b__4_1(HttpClient client) in Startup.cs

client.BaseAddress = new Uri(Configuration["serviceUrl"]);

Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateClient(string name)
Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions+<>c__DisplayClass10_0<TClient, TImplementation>.b__0(IServiceProvider s)
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, ServiceProviderEngineScope scope)
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSite(IServiceCallSite callSite, TArgument argument)
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitTransient(TransientCallSite transientCallSite, ServiceProviderEngineScope scope)
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSite(IServiceCallSite callSite, TArgument argument)
Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine+<>c__DisplayClass1_0.b__0(ServiceProviderEngineScope scope)
Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired)
lambda_method(Closure , IServiceProvider , object[] )
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.DefaultPageModelActivatorProvider+<>c__DisplayClass1_0.b__0(PageContext context)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.DefaultPageModelFactoryProvider+<>c__DisplayClass3_0.b__0(PageContext pageContext)
Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.CreateInstance()
Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.InvokeInnerFilterAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

SqlServer and Sqlite `add package` commands incorrect in `1. Create BackEnd API project.md`

PS C:\Users\geoff\work\ConferencePlanner> dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 3.1.1
Could not find any project in `C:\Users\geoff\work\ConferencePlanner\`.


PS C:\Users\geoff\work\ConferencePlanner> dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 3.1.1
Could not find any project in `C:\Users\geoff\work\ConferencePlanner\`.

SocketException when running the solution

System.Net.Http.HttpRequestException: Aucune connexion n’a pu être établie car l’ordinateur cible l’a expressément refusée ---> System.Net.Sockets.SocketException: Aucune connexion n’a pu être établie car l’ordinateur cible l’a expressément refusée
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
at System.Threading.Tasks.ValueTask1.get_Result() at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Threading.Tasks.ValueTask1.get_Result()
at System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask1 creationTask) at System.Threading.Tasks.ValueTask1.get_Result()
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
at FrontEnd.Services.ApiClient.GetSessionsAsync() in C:\Users\Maher\Documents\GitHub\aspnetcore-app-workshop\src\FrontEnd\Services\ApiClient.cs:line 63
at FrontEnd.Services.ApiClient.GetSessionsByAttendeeAsync(String name) in C:\Users\Maher\Documents\GitHub\aspnetcore-app-workshop\src\FrontEnd\Services\ApiClient.cs:line 147
at FrontEnd.Pages.IndexModel.OnGetAsync(Int32 day) in C:\Users\Maher\Documents\GitHub\aspnetcore-app-workshop\src\FrontEnd\Pages\Index.cshtml.cs:line 43
at Microsoft.AspNetCore.Mvc.RazorPages.Internal.ExecutorFactory.NonGenericTaskHandlerMethod.Execute(Object receiver, Object[] arguments)
at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.InvokeHandlerMethodAsync()
at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.InvokeNextPageFilterAsync()
at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.Rethrow(PageHandlerExecutedContext context)
at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.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.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

PostAsJsonAsync in the System.Net.Http

i was following the insructtion until i stoped at the frontend chapitre because the PostAsJsonAsync Is not valid anymore in this dll System.Net.Http also the other methods ReadAsAsync after my reserch after on google

Database suggestions

I've taken a look at your fine database. I took the liberty to build a diagram using plantuml. It might be easier to understand compared to the one you built using Sql Server Management Studio. Also, some suggestions (to whoever wants to work further with this sample):

  • Define a unique key index on all tables, except the junction tables where the PK already enforces uniqueness. It helps maintain consistency and makes it clear what is the business key. Attendees is a nice example.

Conference
Conference.pdf

Home and My Agenda pages show day buttons for days that don't include any sessions

Updated IndexModel code from OnGetAsync follows. Key was removing the use of Enumerable.Range to generate the day offsets based on the start and end time the first and last sessions in the entire conference, but rather looking at the distinct dates in the actual set of sessions being displayed.

var sessions = await GetSessionsAsync();

var startDate = sessions.Min(s => s.StartTime?.Date);

DayOffsets = sessions.Select(s => s.StartTime?.Date)
                                 .Distinct()
                                 .OrderBy(d => d)
                                 .Select(day => ((int)Math.Floor((day.Value - startDate)?.TotalDays ?? 0),
                                                day?.DayOfWeek))
                                 .ToList();

var filterDate = startDate?.AddDays(day);

Sessions = sessions.Where(s => s.StartTime?.Date == filterDate)
                   .OrderBy(s => s.TrackId)
                   .GroupBy(s => s.StartTime)
                   .OrderBy(g => g.Key);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.