Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Tom Newt 28 posts 182 karma points
    Aug 09, 2023 @ 17:43
    Tom Newt
    0

    Should I be using a surface controller to query an external database?

    We are using Umbraco 10.4 and are trying to create a controller to search an external database and display search results. Ideally I'd like to have a viewmodel containing the form inputs and a list of search results that I can iterate over (e.g. firstname, lastname, position, List

    I've successfully created the database context, added the context to Startup.cs, and injected the context into a controller. Using a surface controller seemed the like the correct option here as I could create the form using BeginUmbracoForm, submit the form to a controller, process the query, and return the results. The problem I am running into is that surface controllers do not have a method which allows me to populate a model with results and return that model to a view.

    The umbraco 10 documentation is very lacking in useful examples when it comes to the different types of controllers. For what I'm trying to accomplish do I have to use a render controller and pass the form values in the querystring?

  • Huw Reddick 1737 posts 6098 karma points MVP c-trib
    Aug 09, 2023 @ 20:37
    Huw Reddick
    0

    You can use just return View("MyView",myModel);

  • Tom Newt 28 posts 182 karma points
    Aug 15, 2023 @ 14:13
    Tom Newt
    0

    Does it matter which controller type I implement between SurfaceController and RenderController?

  • Huw Reddick 1737 posts 6098 karma points MVP c-trib
    Aug 15, 2023 @ 14:17
  • Tom Newt 28 posts 182 karma points
    Aug 24, 2023 @ 18:15
    Tom Newt
    0

    I tried following that guide and based on the description of the controller types I think I should be using a vanilla MVC controller. So along with the umbraco documentation I've tried creating a custom controller.

    Here's my ViewModel:

    public class CountyBirthViewModel : ContentModel
    {
        public CountyBirthViewModel(IPublishedContent content)
            : base(content)
        {
        }
    
        public string FirstName { get; set; } = string.Empty;
        public bool HasSearched { get; set; } = false;
        public IEnumerable<CountyBirthIndex> SearchResults { get; set; } = Enumerable.Empty<CountyBirthIndex>();
    }
    

    Controller:

    usings...
    
    namespace Umbraco_Prod.Controllers
    {
    public class CountyBirthController : UmbracoPageController, IVirtualPageController
    {
        private readonly Library_Context _libraryContext;
        private readonly IPublishedValueFallback _publishedValueFallback;
        private readonly IUmbracoContextAccessor _umbracoContextAccessor;
    
        public CountyBirthController(ILogger<CountyBirthController> logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor, IPublishedValueFallback publishedValueFallback, DplLibrary_Context libraryContext)
            : base(logger, compositeViewEngine)
        {
            _libraryContext = libraryContext;
            _umbracoContextAccessor = umbracoContextAccessor;
            _publishedValueFallback = publishedValueFallback;
        }
    
        public IPublishedContent FindContent(ActionExecutingContext actionExecutingContext)
        {
            if (_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext))
            {
                var countyBirthPage = umbracoContext.Content.GetById(19708);
                if (countyBirthPage != null)
                {
    
                    if (actionExecutingContext.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
                    {
                        // Check which action is executing
                        switch (controllerActionDescriptor.ActionName)
                        {
                            case nameof(Index):
                                return countyBirthPage;
                        }
                    }
    
                    return countyBirthPage;
                }
            }
    
            return null;
        }
    
        [HttpGet]
        public IActionResult Index()
        {
            return View(CurrentPage);
        }
    

    And here's the beginning of my view:

    @using Umbraco.Cms.Web.Common.PublishedModels;
    @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco_Prod.Models.DPL.CountyBirthViewModel>
    @{
        Layout = "Masterpage.cshtml";
    }
    
    ...header html
    
            @*Search Form*@
            <div class="row">
                <div class="col-md-6">
                    <form asp-action="index" method="post">
                        <div class="form-group">
                            <label asp-for="FirstName" class="control-label">First Name</label>
                            <input asp-for="FirstName" class="form-control" />
                        </div>
                        <div class="form-group mt-3">
                            <input type="submit" value="Search" class="btn btn-primary" />
                        </div>
                    </form>
                </div>
            </div>
    

    Finally, here's the error I get from the Index action, "ModelBindingException: Cannot bind source type Umbraco.Cms.Web.Common.PublishedModels.CountyBirth to model type Umbraco_Prod.Models.CountyBirthViewModel. The source is a ModelsBuilder type, but the view model is not. The application is in an unstable state and should be restarted."

    Is there something wrong with my using and inherits statements in the view? Should I be doing this in a render controller instead of vanilla?

  • Huw Reddick 1737 posts 6098 karma points MVP c-trib
    Aug 24, 2023 @ 18:51
    Huw Reddick
    0

    Could be your viewmodel, it should use CountyBirthViewModel : CountyBirth rather than CountyBirthViewModel : ContentModel

  • Tom Newt 28 posts 182 karma points
    Aug 24, 2023 @ 21:30
    Tom Newt
    0

    I've got this working using a RenderController and passing all the form values in the querystring, but that just feels like a sloppy way to go about retrieving and displaying data from an external source. I was hoping I'd be able to do this using a strongly typed form with data binding to the viewmodel, but for that it seems I need to do some sort of mix between render controller for the doc type/template route hijacking and a surface controller for the form; but even if I go that route all the examples I found still pass the form values back to the render controller in the query string. The more I look at this the more it seems like I should have gone with an UmbracoApiController, posted the form through ajax, and build the table from the response.

  • Huw Reddick 1737 posts 6098 karma points MVP c-trib
    Aug 25, 2023 @ 12:21
    Huw Reddick
    100

    If you have a Content Node (page) on which you wish to display data from outside of Umbraco, you can either do this by utilizing a renderController so that your Index action fetches the data and returns it to the page in the PublishedContentWrapper (your viewmodel) or alternatively you can use ajax and a different controller type to reurn a view of the results which get inserted into the page when the ajax post reurns.

Please Sign in or register to post replies

Write your reply to:

Draft