0
votes

Rendre la vue partielle en chaîne HTML dans ASP.NET Core 2.2

J'essaie d'utiliser AJAX pour appeler mon contrôleur et renvoyer une vue partielle avec un modèle sous forme de chaîne afin de pouvoir l'injecter dans mon HTML. J'ai déjà fait cela dans MVC5 en utilisant une interface de contrôleur, mais je n'arrive pas à trouver quoi que ce soit sur la façon de le faire pour une vue partielle dans Asp.Net Core 2.2. J'ai trouvé des exemples de rendu d'une vue en une chaîne, mais je n'ai pas pu les modifier pour qu'ils fonctionnent pour une vue partielle.

Action du contrôleur:

   $.ajax({
      type: "GET",
      url: "../Home/GetUpsertPartialView/",
      data: messageBoardData,
      contentType: 'application/json; charset=utf-8',
      success: function (data) {
         console.log(data);
         $("#messageBoardModalBody").val(data.view);
         $("#messageBoardModal").modal("show");
      }
   });

Appel AJAX:

    public JsonResult GetUpsertPartialView(MessageBoard messageBoard)
    {
        Dictionary<string, string> result = new Dictionary<string, string>();
        string errorState = "0";
        string errorMessage = "";

        try
        {
            result["view"] = ""; // My call to render the Partial View would go here.
        }
        catch (Exception)
        {
            errorState = "1";
            errorMessage = "An error was encountered while constructing the View.";
        }
        result["errorState"] = errorState;
        result["errorMessage"] = errorMessage;
        return Json(result);
    }

J'ai confirmé que mon contrôleur est touché, que les paramètres sont correctement passés et que je reçois les données correctes de l'action à mon appel AJAX. La seule chose qui me manque est la possibilité de rendre une vue partielle directement dans une chaîne.

S'il existe une autre façon de faire cela dans Asp.net Core, je suis ouvert à d'autres options.

Remarque: je fais juste cela pour apprendre Asp.Net Core. Veuillez me faire savoir si des informations supplémentaires sont nécessaires.


0 commentaires

3 Réponses :


4
votes

Pourquoi le résultat Json avec une chaîne html? Vous pouvez renvoyer une vue partielle directement pour renvoyer du HTML.

public IActionResult GetUpsertPartialView(MessageBoard messageBoard)
{

    return PartialView("someviewname", messageBoard);
}


4 commentaires

La plupart du temps, je dois renvoyer des données supplémentaires en dehors de la vue partielle. Plus précisément, je dois pouvoir renvoyer des données d'erreur dans la plupart des cas. C'est pourquoi je souhaite le renvoyer dans le cadre d'un résultat Json.


Je retournerais soit json et utiliserais le json pour créer le html, soit je retournerais simplement la vue partielle, si une erreur se produit, je retournerais simplement NotFound () au lieu de la vue partielle et l'ajax peut savoir que c'était une erreur du code d'état.


C'est une bonne idée. Je suppose que je n'ai pas vraiment besoin de renvoyer un message d'erreur spécifique car il est enregistré dans mon application. Je peux renvoyer différents codes de statut au besoin à la place. Cela répond à toutes mes exigences, je vais donc marquer ceci comme la réponse. Merci!


@JoeAudette Je suis vraiment retournais données supplémentaires. Je pourrais certainement créer le HTML en javascript, mais pourquoi voudrais-je prendre un partiel HTML, le convertir en JSON, puis créer du HTML à partir du JSON?



1
votes

Il est possible d'obtenir une vue partielle (ou plusieurs) de n'importe où (un contrôleur, un modèle de page, etc.) en utilisant un service:

L'Origine de cette réponse , il mérite le crédit (je l'ajoute ici car j'avais besoin de quelque chose comme ça et il m'a fallu un certain temps pour le trouver)

Définition de l'interface pour l'inejection de dépendance

string html = await m_RenderService.RenderToStringAsync("<NameOfPartial>", new Model());

La mise en œuvre du service

services.AddScoped<IViewRenderService, ViewRenderService>();

Ajout de la classe dans la fonction ConfigureServices :

public class ViewRenderService : IViewRenderService
{
    private readonly IRazorViewEngine _razorViewEngine;
    private readonly ITempDataProvider _tempDataProvider;
    private readonly IServiceProvider _serviceProvider;

    public ViewRenderService(IRazorViewEngine razorViewEngine,
        ITempDataProvider tempDataProvider,
        IServiceProvider serviceProvider)
    {
        _razorViewEngine = razorViewEngine;
        _tempDataProvider = tempDataProvider;
        _serviceProvider = serviceProvider;
    }

    public async Task<string> RenderToStringAsync(string viewName, object model)
    {
        var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
        var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

        using (var sw = new StringWriter())
        {
            var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);

            if (viewResult.View == null)
            {
                throw new ArgumentNullException($"{viewName} does not match any available view");
            }

            var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
            {
                Model = model
            };

            var viewContext = new ViewContext(
                actionContext,
                viewResult.View,
                viewDictionary,
                new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
                sw,
                new HtmlHelperOptions()
            );

            await viewResult.View.RenderAsync(viewContext);
            return sw.ToString();
        }
    }
}

Enfin, utiliser le service

public interface IViewRenderService
{
    Task<string> RenderToStringAsync(string viewName, object model);
}


1 commentaires

J'ai terriblement peur que ce (ou des variantes) soit vraiment la seule solution. Il est horriblement encombrant d'obtenir une représentation sous forme de chaîne d'un seul Partiel.



0
votes

En développant la réponse d'Aharon, qui répond à la question du titre "pur" de l'OP sur la façon de rendre un partiel sous forme de chaîne, j'ajoute ma propre solution ci-dessous. Le mien est de le faire directement avec une action de contrôleur.

Bien sûr, l'OP ne devrait pas utiliser cela dans son cas d'utilisation car la réponse exceptée est correcte.

La méthode CreateViewModelAsync est la vôtre.

// SomeController.cs

public SomeController(
    IHtmlGenerator htmlGenerator, ICompositeViewEngine viewEngine,
    IModelMetadataProvider metadataProvider, IViewBufferScope bufferScope,
    HtmlEncoder htmlEncoder, UrlEncoder urlEncoder,
    ModelExpressionProvider modelExpressionProvider)            
{
    this.viewEngine = viewEngine;
    this.cardHtmlHelper = new HtmlHelper<TimesheetCardModel>(
        htmlGenerator, viewEngine, metadataProvider, bufferScope,
        htmlEncoder, urlEncoder, modelExpressionProvider);
}

[HttpGet]
[Route("test", Name = "TestRoute")]
public async Task<IActionResult> GetTest()
{
    // Example renders a partial view as HTML using MotherModel.Children.First() as
    // the model for the partial.

    MotherModel viewModel = await this.CreateViewModelAsync();

    const string viewName = "_MyPartial";

    var foundView = this.viewEngine.FindView(this.ControllerContext, viewName, false);
    var viewData = new ViewDataDictionary<FirstChildModel>(this.ViewData);
    
    var textWriter = new StringWriter();
    var viewContext = new ViewContext(this.ControllerContext, foundView.View, viewData, this.TempData, textWriter, new HtmlHelperOptions());
    
    this.cardHtmlHelper.Contextualize(viewContext);

    var htmlContent = await this.cardHtmlHelper.PartialAsync(viewName, pageModel.Children.First(), viewData);

    htmlContent.WriteTo(textWriter, HtmlEncoder.Default);

    var html = textWriter.ToString();

    ...
}


0 commentaires