namespace Core.Controllers;
public class SBLLandingPageController : RenderController {
private readonly IPublishedValueFallback _publishedValueFallback;
private readonly ISettings _settings;
public SBLLandingPageController(
ILogger<RenderController> logger,
ICompositeViewEngine compositeViewEngine,
IUmbracoContextAccessor umbracoContextAccessor,
IPublishedValueFallback publishedValueFallback,
ISettings settings) : base(logger, compositeViewEngine, umbracoContextAccessor) {
_publishedValueFallback = publishedValueFallback;
_settings = settings;
}
public override IActionResult Index() {
var home = new SbllandingPage(CurrentPage, _publishedValueFallback);
var viewModel = new SbllandingPageViewModel {
Page = home,
Settings = _settings,
ErrorMessage = ModelState.Values.FirstOrDefault()?.Errors?.FirstOrDefault()?.ErrorMessage
};
return View("~/Views/Pages/SBLLandingPage.cshtml", viewModel);
}
}
In the cshtml file, I want to use the "GetAltinnUrl" method with umbraco forms.
I have tried literally 500 different ways of doing so.
I either get the message "Could not find a Surface controller route in the RouteTable for controller name" or "415 Unsupported Media Type" or nothing is happening at all.
I tried all four of these but non worked:
@using (Html.BeginUmbracoForm<SBLLandingPageController>("GetAltinnUrl", "SBLLandingPageController", FormMethod.Post)) {
@using (Html.BeginUmbracoForm("GetAltinnUrl", "SBLLandingPage", new {}, new {@class = "consent-form"})) {
@using (Html.BeginUmbracoForm<SBLLandingPageController>("GetAltinnUrl")) {
@using (Html.BeginForm("GetAltinnUrl", "SBLApi", FormMethod.Post, new { @class = "consent-form" })) {
I stopped to understand what is actually happening here. Maybe I also got the controller types confused, but the rest works fine like this.
Oh yes. you are in fact right, thank you.
I have replaced the API Controller with a SurfaceController. Now, all error messages are gone, but it doesnt do anything anyway.
It does a post and has a ERROR 400 Bad Request. In fact, it never calls the GetAltInnUrl. this is weird because it obviously can find it, because if I write in something else there, I get the error that it cannot find it.
using Core.Constants;
using Core.Helpers;
using Core.Interfaces;
using Core.SBL;
using Core.ViewModels;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Logging;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Web.Common;
using Umbraco.Cms.Web.Common.Controllers;
using Umbraco.Cms.Web.Website.Controllers;
using Umbraco.Extensions;
namespace Core.Controllers;
public class SBLApiController: SurfaceController {
private static readonly string ServiceUrl = AppSettingsHelper.GetKey<string>("SBL:SBLService");
private readonly UmbracoHelper _umbracoHelper;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly ILogger<RenderController> _logger;
private readonly IHttpService _httpService;
public SBLApiController(IUmbracoContextAccessor umbracoContextAccessor,
IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches,
IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider, UmbracoHelper umbracoHelper, IHttpContextAccessor httpContextAccessor, ILogger<RenderController> logger, IHttpService httpService) : base(umbracoContextAccessor,
databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) {
_umbracoHelper = umbracoHelper;
_httpContextAccessor = httpContextAccessor;
_umbracoContextAccessor = umbracoContextAccessor;
_logger = logger;
_httpService = httpService;
}
[HttpPost]
[ValidateAntiForgeryToken]
//[ActionName("GetAltinnUrl")]
//[Route("sbl/getAltInnUrl")]
public async Task<ActionResult> GetAltinnUrl(SsnFormViewModel model) {
Console.WriteLine("I AM CALLED");
var currentPage = _umbracoContextAccessor.GetRequiredUmbracoContext().PublishedRequest?.PublishedContent;
try {
bool.TryParse(AppSettingsHelper.GetKey<string>("SBL:SBLUseMockData"), out var useMockData);
// In test environments we need to fetch an authentication code from Altinn manually. This is done
// by calling the api/sbl-process/initialize/ call in the DPloy API. In the production environment the
// authentication code will be fetched from the URL parameter.
if (useMockData && string.IsNullOrWhiteSpace(model.AuthenticationCode)) {
model.AuthenticationCode = await GetMockupAuthenticationCode();
}
if (string.IsNullOrWhiteSpace(model.AuthenticationCode)) {
throw new ArgumentException("Authentication code is not present");
}
var altinnUrl = string.Format(AppSettingsHelper.GetKey<string>("SBL:SBLAltinnUrl"), model.AuthenticationCode);
Console.WriteLine(altinnUrl);
Console.WriteLine("Redirect 1");
return Redirect(altinnUrl);
} catch (Exception e) {
_logger.LogError($"An error occured while constructing Altinn URL {e}", e);
var httpContext = _httpContextAccessor.HttpContext;
httpContext?.Session.SetString("Consent", AltinnStatus.Error);
Console.WriteLine("Redirect 2");
}
Console.WriteLine("Redirect 3");
return Redirect(currentPage?.Url() ?? "/");
}
private async Task<string> GetMockupAuthenticationCode() {
//_httpContextAccessor.HttpContext.Request.GetEncodedUrl()
var httpContext = _httpContextAccessor.HttpContext;
var host = httpContext?.Request.Scheme + "://" + httpContext?.Request.Host;
var callback = host + Url.Action("ReceiveConsent");
var initializeUrl = ServiceUrl + AppSettingsHelper.GetKey<string>("SBL:SBLInitialize");
var mockData = new {
consentCaseReference = "123",
personIdentifier = "01029413157",
lastName = "Høk",
email = "[email protected]",
handleUserCommunication = false,
redirectUrl=callback,
notificationUrl = "http://localhost:19355/sblwebapi/api/notifyapplikator",
validTo = DateTime.Now.AddDays(1)
};
var result =
await _httpService.Post<AltinnInitializationResponse, object>(initializeUrl, mockData);
return result == null ? string.Empty : result.AuthorizationCode;
}
public async Task<ActionResult> ReceiveConsent(string authorizationCode, string status, string failedAuthorizationCode, string errorMessage) {
if (!string.IsNullOrWhiteSpace(errorMessage)) {
_logger.LogWarning("Altinn returned an error message when returning from consent: \"" + errorMessage + "\"");
}
try {
var httpContext = _httpContextAccessor.HttpContext;
var pageId = httpContext?.Session.GetInt32(SessionKeys.SBLLandingPageId);
_httpContextAccessor.HttpContext?.Session.Remove(SessionKeys.SBLLandingPageId);
var updateUrl = ServiceUrl + AppSettingsHelper.GetKey<string>("SBL:SBLUpdate");
// If a user rejects SBL then Altinn sets the authCode to failedAuthenticationCode rather then
// authenticationCode. Status is also set to "Failed"
var authCode = authorizationCode;
var hasRejected = false;
if (status == AltinnStatus.Failed) {
authCode = authorizationCode;// ?? failedAuthorizationCode;
hasRejected = true;
}
// Triggers an update call within DPloy to update SBL status
// Send put request to Dploy
await _httpService.Put<DployUpdateResultModel, object>(updateUrl, new {
AuthorizationCode = authCode,
reject = hasRejected
});
httpContext?.Session.SetString("Consent", status);
if (pageId <= 0) {
throw new Exception("Page Id is not set.");
}
var redirectPage = _umbracoHelper.Content(pageId);
return Redirect(redirectPage?.Url() ?? "/");
} catch (Exception e) {
_logger.LogError($"An error occured while handling the Altinn response {e}", e);
}
return Redirect("/");
}
}
public class DployUpdateResultModel {
public string? Status { get; set; }
}
class AltinnInitializationResponse {
public string? AuthorizationCode { get; set; }
}
The commented lines are all sorts of things I tried here.
Thank you for the link, this seems to be the only of the 500 links I havent read through yet, I will have a look 😁
Redirect forms correctly with both API Controller and Render Controller
I have two classes, one being an RenderController and one being an API Controller
They look like this:
}
and
In the cshtml file, I want to use the "GetAltinnUrl" method with umbraco forms. I have tried literally 500 different ways of doing so. I either get the message "Could not find a Surface controller route in the RouteTable for controller name" or "415 Unsupported Media Type" or nothing is happening at all.
I tried all four of these but non worked:
I stopped to understand what is actually happening here. Maybe I also got the controller types confused, but the rest works fine like this.
Hi Manfred
I think you should be using a surfacecontroller for this,
Html.BeginUmbracoForm
is for posting to a SurfaceController.Oh yes. you are in fact right, thank you. I have replaced the API Controller with a SurfaceController. Now, all error messages are gone, but it doesnt do anything anyway.
It does a post and has a ERROR 400 Bad Request. In fact, it never calls the GetAltInnUrl. this is weird because it obviously can find it, because if I write in something else there, I get the error that it cannot find it.
What does your form code look like in the view?
There is a decent example in the docs https://docs.umbraco.com/umbraco-cms/tutorials/members-registration-and-login#assigning-new-members-to-groups-automatically
The code of my view looks like this:
The commented lines are all sorts of things I tried here. Thank you for the link, this seems to be the only of the 500 links I havent read through yet, I will have a look 😁
you shouldn't need this line @Html.AntiForgeryToken() (should be added by Umbraco)
You may need to use bind prefix in your method.
A quick way to test it is reaching your method is to change it to
It should then hit your method regardless of what you are passing to it, you can then try and figure out what it should be expecting :)
is working on a reply...