Skip to content

Commit

Permalink
add newrelic example app (#254)
Browse files Browse the repository at this point in the history
  • Loading branch information
jenschude authored Nov 16, 2023
1 parent 25cf6e6 commit 575bb2b
Show file tree
Hide file tree
Showing 80 changed files with 41,322 additions and 1 deletion.
34 changes: 34 additions & 0 deletions commercetools.Sdk/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# First stage
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /DockerSource

# Copy csproj and restore as distinct layers
COPY . ./src/
WORKDIR /DockerSource/src

RUN dotnet restore

RUN dotnet publish -c release -o /DockerOutput/app --no-restore Examples/commercetools.Api.NewRelicExample

# Final stage
FROM mcr.microsoft.com/dotnet/aspnet:7.0

# Install the agent
RUN apt-get update && apt-get install -y wget ca-certificates gnupg \
&& echo 'deb http://apt.newrelic.com/debian/ newrelic non-free' | tee /etc/apt/sources.list.d/newrelic.list \
&& wget https://download.newrelic.com/548C16BF.gpg \
&& apt-key add 548C16BF.gpg \
&& apt-get update \
&& apt-get install -y newrelic-dotnet-agent \
&& rm -rf /var/lib/apt/lists/*

# Enable the agent
ENV CORECLR_ENABLE_PROFILING=1 \
CORECLR_PROFILER={36032161-FFC0-4B61-B559-F6C5D41BAE5A} \
CORECLR_NEWRELIC_HOME=/usr/local/newrelic-dotnet-agent \
CORECLR_PROFILER_PATH=/usr/local/newrelic-dotnet-agent/libNewRelicProfiler.so \
NEW_RELIC_APP_NAME=commercetools-newrelic-example

WORKDIR /DockerOutput/app
COPY --from=build /DockerOutput/app ./
ENTRYPOINT ["dotnet", "commercetools.Api.NewRelicExample.dll"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Threading.Tasks;
using commercetools.Api.NewRelicExample.Models;
using commercetools.Api.NewRelicExample.Services;
using commercetools.Base.Client;
using commercetools.Base.Client.Tokens;
using Microsoft.AspNetCore.Mvc;

namespace commercetools.Api.NewRelicExample.Controllers
{
public class BaseController : Controller
{
protected readonly IClient _client;
protected readonly IUserCredentialsStoreManager _userCredentialsStore;
protected readonly MeServices _meServices;
protected readonly CartServices _cartServices;

public BaseController(IClient client,
IUserCredentialsStoreManager userCredentialsStore,
MeServices meServices,
CartServices cartServices)
{
this._client = client;
this._userCredentialsStore = userCredentialsStore;
this._meServices = meServices;
this._cartServices = cartServices;
}

public async Task<CustomerProfileViewModel> GetCurrentCustomerProfile()
{
var profileViewModel = new CustomerProfileViewModel();
var meProfile = await _meServices.GetMyProfile();
profileViewModel.ActiveCart = await _cartServices.GetActiveCartViewModel();
if (meProfile != null)
{
var baseInfo = new BaseCustomer(meProfile);
profileViewModel.Customer = baseInfo;
}

return profileViewModel;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.Threading.Tasks;
using commercetools.Api.NewRelicExample.Models;
using commercetools.Api.NewRelicExample.Services;
using commercetools.Sdk.Api.Models.Me;
using commercetools.Sdk.Api.Models.Products;
using commercetools.Base.Client;
using commercetools.Base.Client.Tokens;
using Microsoft.AspNetCore.Mvc;

namespace commercetools.Api.NewRelicExample.Controllers
{
public class HomeController : BaseController
{
private readonly ProductServices _productServices;
public HomeController(IClient client,
IUserCredentialsStoreManager userCredentialsStore,
MeServices meServices,
CartServices cartServices, ProductServices productServices)
: base(client, userCredentialsStore, meServices, cartServices)
{
this._productServices = productServices;
}

public async Task<IActionResult> Index()
{
var products = await _productServices.GetAllPublishedProducts();
var customerProfile = await GetCurrentCustomerProfile();
var homeModel = new HomeViewModel(products, customerProfile);
return View(homeModel);
}

public async Task<IActionResult> AddToCart(IProductProjection product)
{
var cartDraft = GetCartDraft();
var cart = await _cartServices.CreateCartForCurrentCustomer(cartDraft);
await _cartServices.AddProductToCurrentActiveCart(cart, product);
return RedirectToAction("Index");
}

private IMyCartDraft GetCartDraft()
{
var cartDraft = new MyCartDraft
{
Currency = Settings.DefaultCurrency,
};
return cartDraft;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Threading.Tasks;
using commercetools.Api.NewRelicExample.Models;
using commercetools.Api.NewRelicExample.Services;
using commercetools.Base.Client;
using commercetools.Base.Client.Tokens;
using Microsoft.AspNetCore.Mvc;

namespace commercetools.Api.NewRelicExample.Controllers
{
public class MeController : BaseController
{
public MeController(IClient client,
MeServices meServices,
CartServices cartServices,
IUserCredentialsStoreManager userCredentialsStoreManager)
: base(client, userCredentialsStoreManager, meServices, cartServices)
{
}

public async Task<IActionResult> SignIn()
{
var customerProfile = await GetCurrentCustomerProfile();
return View(new SignInCustomerViewModel(customerProfile));
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SignIn(SignInCustomerViewModel model)
{
if (ModelState.IsValid)
{
var signInResult = await _meServices.SignIn(model.Email, model.Password);
if (signInResult.IsValidCredentials)
{
//after signin, the anonymous access token and refresh token are immediately invalid
//we need to get new access and refresh tokens with the password flow
_userCredentialsStore.StoreUserCredentialsAndClearToken(model.Email, model.Password);
return RedirectToAction("Index", "MyCart");
}

else
{
model.ResetAfterLoginFailed();
}
}
return View("SignIn", model);
}

public async Task<IActionResult> Logout()
{
await Task.CompletedTask;
_userCredentialsStore.ClearCredentialsAndToken();
return RedirectToAction("Index", "Home");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Threading.Tasks;
using commercetools.Api.NewRelicExample.Services;
using commercetools.Base.Client;
using commercetools.Base.Client.Tokens;
using Microsoft.AspNetCore.Mvc;

namespace commercetools.Api.NewRelicExample.Controllers
{
public class MyCartController : BaseController
{
public MyCartController(IClient client,
CartServices cartServices,
MeServices meServices,
IUserCredentialsStoreManager userCredentialsStoreManager)
: base(client, userCredentialsStoreManager, meServices, cartServices)
{
}

public async Task<IActionResult> Index()
{
var customerProfile = await GetCurrentCustomerProfile();
return View(customerProfile);
}

public async Task<IActionResult> Delete(string lineItemId)
{
var myCart = await _cartServices.DeleteLineItem(lineItemId);
return RedirectToAction("Index");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
using System;
using System.Net.Http;
using commercetools.Sdk.Api.Models.Errors;
using commercetools.Base.Client;
using commercetools.Base.Client.Tokens;
using commercetools.Sdk.Api;
using commercetools.Sdk.Api.Serialization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace commercetools.Api.NewRelicExample.Extensions
{
public static class ClientInjectionSetup
{
/// <summary>
/// Inject Scoped Client per each Request
/// </summary>
/// <param name="services">services container</param>
/// <param name="configuration"></param>
/// <param name="clientName"></param>
public static IHttpClientBuilder UseCommercetoolsScopedClient(this IServiceCollection services,
IConfiguration configuration,
string clientName)
{
services.UseCommercetoolsApiSerialization();
services.UseScopedCredentialsStoreManagers(clientName, configuration);
services.UseScopedTokenProvider(clientName, configuration);

//Create Client with proper TokenProvider as scoped service
services.AddScoped(serviceProvider =>
{
var clientConfiguration = configuration.GetSection(clientName).Get<ClientConfiguration>();
var tokenProvider = serviceProvider.GetService<ITokenProvider>();
var client = ClientFactory.Create(clientName, clientConfiguration,
serviceProvider.GetService<IHttpClientFactory>(),
serviceProvider.GetService<IApiSerializerService>(),
tokenProvider);
client.Name = clientName;
return client;
});

//Add the httpClient and setup the Middlewares
return services.SetupClient(clientName,
errorTypeMapper => typeof(ErrorResponse),
serviceProvider => serviceProvider.GetService<IApiSerializerService>());
}


/// <summary>
/// Inject two instance, one for IAnonymousCredentialsStoreManager and other for IUserCredentialsStoreManager
/// </summary>
/// <param name="services"></param>
/// <param name="clientName"></param>
/// <param name="configuration"></param>
public static void UseScopedCredentialsStoreManagers(this IServiceCollection services,
string clientName,
IConfiguration configuration)
{
services.AddScoped<IAnonymousCredentialsStoreManager>(serviceProvider =>
{
var inCookiesStoreManager = serviceProvider.GetService<InCookiesStoreManager>();
var inSessionStoreManager = serviceProvider.GetService<InSessionStoreManager>();
var anonymousIdStore = new InSessionAnonymousCredentialsStoreManager(inSessionStoreManager, inCookiesStoreManager);
return anonymousIdStore;
});
services.AddScoped<IUserCredentialsStoreManager>(serviceProvider =>
{
var inCookiesStoreManager = serviceProvider.GetService<InCookiesStoreManager>();
var inSessionStoreManager = serviceProvider.GetService<InSessionStoreManager>();
var userCredentialsStore = new InSessionUserCredentialsStoreManager(inSessionStoreManager, inCookiesStoreManager);
return userCredentialsStore;
});
}

/// <summary>
/// Inject scoped tokenProvider based on current tokenFlow
/// </summary>
/// <param name="services"></param>
/// <param name="clientName"></param>
/// <param name="configuration"></param>
public static void UseScopedTokenProvider(this IServiceCollection services,
string clientName,
IConfiguration configuration)
{
services.AddScoped(serviceProvider =>
{
var clientConfiguration = configuration.GetSection(clientName).Get<ClientConfiguration>();
var httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();
var currentTokenFlow = GetCurrentTokenFlow(serviceProvider);
ITokenProvider tokenProvider = null;
if (currentTokenFlow == TokenFlow.Password)
{
var userCredentialsStore = serviceProvider.GetService<IUserCredentialsStoreManager>();
tokenProvider = TokenProviderFactory.CreatePasswordTokenProvider(
clientConfiguration, httpClientFactory, userCredentialsStore);
}
else
{
var anonymousIdStore = serviceProvider.GetService<IAnonymousCredentialsStoreManager>();
if (anonymousIdStore != null && anonymousIdStore.Token == null)
{
anonymousIdStore.AnonymousId = Guid.NewGuid().ToString();
}
tokenProvider = TokenProviderFactory.CreateAnonymousSessionTokenProvider(
clientConfiguration, httpClientFactory, anonymousIdStore);
}
return tokenProvider;
});
}

public static TokenFlow GetCurrentTokenFlow(IServiceProvider serviceProvider)
{
var tokenFlow = TokenFlow.AnonymousSession;
var userCredentialsStore = serviceProvider.GetService<IUserCredentialsStoreManager>();
if (userCredentialsStore != null && !string.IsNullOrEmpty(userCredentialsStore.Username))
{
tokenFlow = TokenFlow.Password;
}
return tokenFlow;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using commercetools.Api.NewRelicExample.Services;
using Microsoft.AspNetCore.Http;

namespace commercetools.Api.NewRelicExample.Extensions
{
public class InCookiesStoreManager
{
private readonly IHttpContextAccessor _httpContextAccessor;

public InCookiesStoreManager(IHttpContextAccessor httpContextAccessor)
{
this._httpContextAccessor = httpContextAccessor;
}

public void SetInCookie(string key, string value)
{
var response = _httpContextAccessor?.HttpContext?.Response;
response?.Cookies.Append(key, value,
new CookieOptions()
{
Path = "/",
Secure = true,
HttpOnly = true,
Expires = DateTimeOffset.Now.AddDays(Settings.ExpireInDays)
});
}
public string GetFromCookie(string key)
{
var request = _httpContextAccessor?.HttpContext?.Request;
return request?.Cookies[key];
}
public void ClearCookie(string key)
{
var response = _httpContextAccessor?.HttpContext?.Response;
response?.Cookies.Delete(key);
}
}
}
Loading

0 comments on commit 575bb2b

Please sign in to comment.