Complete local setup of dev environment
Step 1
Install SqlServer Developer Edition on your machine. This should give you a connection string such as:
Server=localhost;Database=master;Trusted_Connection=True;
Step 2
Use database management tool of your choice and after you connect to the database, run the following queries:
use master;
CREATE DATABASE [sqldb-insight-local];
CREATE DATABASE [sqldb-insight-users-local];
Step 3
Now, the connection strings to the two databases will be:
Server=localhost;Database=sqldb-insight-local;Trusted_Connection=True TrustServerCertificate=True;
Server=localhost;Database=sqldb-insight-users-local;Trusted_Connection=True TrustServerCertificate=True;
and the corresponding commands to set user-secrets will be:
dotnet user-secrets set "ConnectionStrings:Database" "Server=localhost;Database=sqldb-insight-local;Trusted_Connection=True;TrustServerCertificate=True;"
dotnet user-secrets set "ConnectionStrings:UserDatabase" "Server=localhost;Database=sqldb-insight-users-local;Trusted_Connection=True;TrustServerCertificate=True;"
Step 4
Use framework-models and framework-data repositories to setup new data-migrations if needed for sqldb-insight-local db. Utilize auth-server-data repository and any updates/migrations that need to be created for the sqldb-insight-users-local db.
Please make sure the correct connection strings (listed above) are used to create the databases.
Step 5
After you apply the migrations, you should be able to see all the tables created in the appropriate database.
Step 6
Fake data (only supported for non-user database for now) can then be inserted into this local db using the manage-testing-setup project.
Step 7
Make following changes to the study design api:
- Make sure the startup allows for anonymous access to the endpoints:
app.UseEndpoints(endpoints =>
{
if (env.IsDevelopment())
{
endpoints.MapControllers().WithMetadata(new AllowAnonymousAttribute()).AllowAnonymous();
}
else
endpoints.MapControllers();
});
- Manually add the userid that is associated with the test data (can be obtained from the
manage-test-setupproject) in theGetSummariesendpoint in theStudiesController.
public async Task<IActionResult> GetSummaries([FromQuery] PaginationFilter paginationFilter)
{
var userIdStr = HttpContext.GetUserIdForRequest();
userIdStr = "0ee85123-e4b7-484f-bc64-08da3aa68e50";
...// rest of the code
}
Deploy study-design-api using the new connection strings.
Step 8
Make the following changes to the study-design-website project
Program.cs
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using WebApp.Client;
using WebApp.Client.Services.Implementations;
using WebApp.Client.Services.Interfaces;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddAntDesign();
//Add an HttpClient service for making authorized calls to the api
builder.Services.AddHttpClient("api", cl =>
{
cl.BaseAddress = new Uri(builder.Configuration["Addresses:WebAPI"]);
});
builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("api"));
builder.Services.AddSingleton<IHttpService, HttpService>();
builder.Services.AddSingleton<IAssessmentService, AssessmentService>();
builder.Services.AddSingleton<IGroupService, GroupService>();
builder.Services.AddSingleton<IQuestionService, QuestionService>();
builder.Services.AddSingleton<IParticipantService, ParticipantService>();
builder.Services.AddSingleton<IPermissionService, PermissionService>();
builder.Services.AddSingleton<IReportService, ReportService>();
builder.Services.AddSingleton<IStageService, StageService>();
builder.Services.AddSingleton<IStudyService, StudyService>();
builder.Services.AddSingleton<IUserRolesService, UserRolesService>();
await builder.Build().RunAsync();
App.razor
@*<CascadingAuthenticationState>*@
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
@*<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<Authorizing>
<Result Icon="loading-outline"
Title="Logging you in...">
</Result>
</Authorizing>
</AuthorizeRouteView>*@
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
@*</CascadingAuthenticationState>*@
<AntContainer />
MainLayout.razor
@inherits LayoutComponentBase
@inject IStudyService StudyService
@inject NavigationManager Navigation
@*@inject AuthenticationStateProvider _authenticationStateProvider*@
@using WebApp.Client.Services.Interfaces;
@using System.Text.Json;
@using WebApp.Client.Pages;
@using WebApp.Client.Pages.SiderNav;
<Layout>
<Header Class="header">
<Row Style="height:100%;">
<GridCol Span="4" Style="display: flex; align-items: center;">
<img class="insightlogo" src="images/Insight_Icon-transparent.svg" alt="Insight logo" /><span style="color: #c60131; font-size: 28px; font-weight: bold; padding: 0 0 0 0.5rem">Insight</span>
</GridCol>
<GridCol Span="18" Style="text-align:center;">
@if (StudyService.SelectedStudy != null)
{
<span style="font-size: x-large; font-weight: bold;">@StudyService.SelectedStudySummary.Name</span>
}
</GridCol>
@*<GridCol Span="2" Style="text-align: right;">
<LoginDisplay />
</GridCol>*@
</Row>
</Header>
@if (hasRunInit)
{
<Layout>
<SiderNav />
@if (StudyService.SelectedStudy != null)
{
<Content>
@*@Body*@
<WebApp.Client.Pages.Studies.Study/>
</Content>
}
else
{
<Content Class="site-layout-background" Style="min-height:100vh;">
<Layout Style="padding: 30px 120px 120px; background-color: white;">
<PageHeader Class="site-page-header" Style="background-color: lightgray;" Title="@_title" Subtitle="" OnBack="@(()=> { Console.WriteLine("OnBack");})" />
<br />
</Layout>
</Content>
}
</Layout>
}
else
{
@Body
}
</Layout>
@code{
private string _title = "Please select your study to get started!";
//[CascadingParameter] protected Task<AuthenticationState> AuthState { get; set; }
public bool hasRunInit;
protected override async Task OnInitializedAsync()
{
base.OnInitialized();
Console.WriteLine("MainLayout -> OnInitializedAsync");
//_authenticationStateProvider.AuthenticationStateChanged += this.OnAuthenticationStateChanged;
//// If the user is authenticated and reloads the page in the browser, the event won't trigger so we can do the initial load here.
//var user = (await _authenticationStateProvider.GetAuthenticationStateAsync()).User;
//Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " InitialDataLoader -> OnInitializedAsync -> IsUserAuthenticated: " + user.Identity.IsAuthenticated);
//if (user.Identity.IsAuthenticated)
//{
hasRunInit = true;
// Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " InitialDataLoader -> OnInitializedAsync -> InitUser");
//}
//else
//{
// Navigation.NavigateTo(
// $"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}");
//}
StudyService.OnChange += StateHasChanged;
@*var user = (await AuthState).User;
if (!user.Identity.IsAuthenticated)
{
Navigation.NavigateTo(
$"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}");
}*@
}
private async void OnAuthenticationStateChanged(Task<AuthenticationState> task)
{
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " InitialDataLoader -> OnAuthenticationStateChanged -> " + Navigation.Uri);
var user = (await task).User;
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " InitialDataLoader -> OnAuthenticationStateChanged -> IsUserAuthenticated: " + user.Identity.IsAuthenticated);
if (user.Identity.IsAuthenticated)
{
if (Navigation.Uri.Contains("/authentication/login-callback?code") && !hasRunInit)
{
Console.WriteLine("Updating MainLayout to show other UI elements.");
hasRunInit = true;
}
@*if (!hasRunInit)
{
hasRunInit = true;
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " CascadingAppStateProvider -> OnInitializedAsync -> InitUser");
Console.WriteLine("User authenticated for the first time.");
}
else
{
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " InitialDataLoader -> OnInitializedAsync -> Init has already been triggered!");
Console.WriteLine("User authenticated for the second or probably more time");
}*@
}
}
}
<style>
#components-layout-demo-top-side-2 .logo {
width: 120px;
height: 31px;
color: white;
margin: 16px 28px 16px 0;
float: left;
}
.site-layout-background {
background: white;
}
.header {
z-index: 10;
background-color: white;
padding: 0 1.5rem;
box-shadow: 0 2px 8px #f0f1f2;
}
.insightlogo {
width: 50px;
padding-top: 2px;
padding-left: 2px;
}
</style>