在.NET Core中将视图返回为字符串

Has*_*sef 53 c# asp.net razor .net-core asp.net-core

我发现了一些文章如何在ASP.NET中将视图返回到字符串,但无法转换为能够使用.NET Core运行它

public static string RenderViewToString(this Controller controller, string viewName, object model)
{
    var context = controller.ControllerContext;
    if (string.IsNullOrEmpty(viewName))
        viewName = context.RouteData.GetRequiredString("action");

    var viewData = new ViewDataDictionary(model);

    using (var sw = new StringWriter())
    {
        var viewResult = ViewEngines.Engines.FindPartialView(context, viewName);
        var viewContext = new ViewContext(context, viewResult.View, viewData, new TempDataDictionary(), sw);
        viewResult.View.Render(viewContext, sw);

        return sw.GetStringBuilder().ToString();
    }
}
Run Code Online (Sandbox Code Playgroud)

假设能够使用以下控制器从控制器调用:

var strView = this.RenderViewToString("YourViewName", yourModel);
Run Code Online (Sandbox Code Playgroud)

当我尝试将上述内容运行到.NET Core时,我遇到了很多编译错误.

我试图将其转换为使用.NET Core,但失败了,任何人都可以帮助提及所需的using ..和所需"dependencies": { "Microsoft.AspNetCore.Mvc": "1.1.0", ... },project.json.

其他一些示例代码在这里,这里这里

注意 我需要解决方案来将视图转换为string.NET Core,无论相同的代码是否被转换,或者其他方式可以做到.

Red*_*Red 69

如果像我一样,你有许多需要这个的控制器,比如在报告网站中,重复这段代码并不是很理想,甚至注入或调用另一个服务似乎并不合适.

所以我已经制作了我自己的上述版本,但有以下不同之处:

  • 模型强类型
  • 查找视图时的错误检查
  • 将视图呈现为部分或页面的能力
  • asynchronus
  • 实现为控制器扩展
  • 不需要DI

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Rendering;
    using Microsoft.AspNetCore.Mvc.ViewEngines;
    using Microsoft.AspNetCore.Mvc.ViewFeatures;
    using System.IO;
    using System.Threading.Tasks;
    
    namespace CC.Web.Helpers
    {
        public static class ControllerExtensions
        {
            public static async Task<string> RenderViewAsync<TModel>(this Controller controller, string viewName, TModel model, bool partial = false)
            {
                if (string.IsNullOrEmpty(viewName))
                {
                    viewName = controller.ControllerContext.ActionDescriptor.ActionName;
                }
    
                controller.ViewData.Model = model;
    
                using (var writer = new StringWriter())
                {
                    IViewEngine viewEngine = controller.HttpContext.RequestServices.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
                    ViewEngineResult viewResult = viewEngine.FindView(controller.ControllerContext, viewName, !partial);
    
                    if (viewResult.Success == false)
                    {
                        return $"A view with the name {viewName} could not be found";
                    }
    
                    ViewContext viewContext = new ViewContext(
                        controller.ControllerContext,
                        viewResult.View,
                        controller.ViewData,
                        controller.TempData,
                        writer,
                        new HtmlHelperOptions()
                    );
    
                    await viewResult.View.RenderAsync(viewContext);
    
                    return writer.GetStringBuilder().ToString();
                }
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

然后执行:

viewHtml = await this.RenderViewAsync("Report", model);
Run Code Online (Sandbox Code Playgroud)

或者这对于PartialView:

partialViewHtml = await this.RenderViewAsync("Report", model, true);
Run Code Online (Sandbox Code Playgroud)

  • 这应该是更多的方式.它看起来更优雅,它对我来说就像一个魅力. (9认同)
  • 如果找不到视图,我宁愿抛出异常,而不是得到令人惊讶的结果:`return $"A view with the name {viewName} Could not be find";` (3认同)
  • 谢谢,优秀的解决方案 我唯一改变的是为部分视图添加一个额外的包装扩展方法.我在使用之前注入的ViewRenderService时遇到了一些问题,因为它可以从其他控制器的视图树访问部分视图.这些视图确实正确呈现,但在调试期间永远不会自动重新编译,将它们移动到共享视图解决了问题! (2认同)
  • 如果您的视图位于不寻常的位置,则此方法不起作用。我在自己的答案中发布了修复程序。 (2认同)
  • 这是在服务器上运行的,因此不会执行客户端代码。如果您无法重构以使用模型数据,我认为您不走运 (2认同)

Has*_*sef 42

感谢Paris Polyzos和他的文章.

我在这里重新发布他的代码,以防原始帖子因任何原因被删除.

Service在文件中创建viewToString.cs如下代码:

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;
 
namespace WebApplication.Services
{
    public interface IViewRenderService
    {
        Task<string> RenderToStringAsync(string viewName, object model);
    }
 
    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();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 将服务添加到Startup.cs文件中,如下所示:

    using WebApplication.Services;
    
    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddScoped<IViewRenderService, ViewRenderService>();
     }
    
    Run Code Online (Sandbox Code Playgroud)

添加"preserveCompilationContext": truebuildOptionsproject.json,所以文件看起来像:

{
  "version": "1.0.0-*",
  "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },
  "dependencies": {
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
    "Microsoft.AspNetCore.Mvc": "1.0.1"
  },
  "frameworks": {
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.1"
        }
      },
      "imports": "dnxcore50"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)
  1. 定义你model,例如:

    public class InviteViewModel {
        public string   UserId {get; set;}
        public string   UserName {get; set;}
        public string   ReferralCode {get; set;}
        public int  Credits {get; set;}
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创建你Invite.cshtml的例子:

    @{
        ViewData["Title"] = "Contact";
    }
    @ViewData["Title"].
    user id: @Model.UserId
    
    Run Code Online (Sandbox Code Playgroud)
  3. Controller:

一个.在开头定义以下内容:

private readonly IViewRenderService _viewRenderService;
 
public RenderController(IViewRenderService viewRenderService)
{
    _viewRenderService = viewRenderService;
}
Run Code Online (Sandbox Code Playgroud)

湾 使用模型调用并返回视图,如下所示:

var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
return Content(result);
Run Code Online (Sandbox Code Playgroud)

C.完整的控制器示例,可能是:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

using WebApplication.Services;

namespace WebApplication.Controllers
{
[Route("render")]
public class RenderController : Controller
{
    private readonly IViewRenderService _viewRenderService;
 
    public RenderController(IViewRenderService viewRenderService)
    {
        _viewRenderService = viewRenderService;
    }
 
    [Route("invite")]
    public async Task<IActionResult> RenderInviteView()
    {
        ViewData["Message"] = "Your application description page.";
        var viewModel = new InviteViewModel
        {
            UserId = "cdb86aea-e3d6-4fdd-9b7f-55e12b710f78",
            UserName = "Hasan",
            ReferralCode = "55e12b710f78",
            Credits = 10
        };
 
        var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
        return Content(result);
    }
}

public class InviteViewModel {
        public string   UserId {get; set;}
        public string   UserName {get; set;}
        public string   ReferralCode {get; set;}
        public int  Credits {get; set;}
} 
}
Run Code Online (Sandbox Code Playgroud)

  • 这几乎适用于Core 2.0,但有两个例外:(1)_razorViewEngine.FindView在绝对路径上不起作用,我至少需要这些,因为标准模板应用程序不使用它假定的Views文件夹.Tto使用他在Core 2.0 GitHub站点上被记录为"按设计",解决方案是使用_razorViewEngine.GetView,它支持绝对路径.(2)没有解释preserveCompilationContext(不在原文中) - 为什么需要它?目前尚不清楚在哪里使用COre 2.0,它似乎没有它. (11认同)
  • 使用此代码ViewData ["Message"] ="您的应用程序描述页面."; 在视图中将为null.为什么?任何人都可以发布一个包含正确处理ViewData的固定版本,而不仅仅是视图模型. (2认同)

HMZ*_*HMZ 23

ASP.NET 核心 3.1

我知道这里有很多好的答案,我想我也分享我的:

这是从 GitHub 上的 asp.net core 的源代码中提取的,我通常使用它来使用 Razor 呈现 HTML 电子邮件以及通过 Ajax 或 SignalR 返回部分视图的 HTML。

添加为瞬态服务并在控制器中注入 DI

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Abstractions;
    using Microsoft.AspNetCore.Mvc.ModelBinding;
    using Microsoft.AspNetCore.Mvc.Razor;
    using Microsoft.AspNetCore.Mvc.Rendering;
    using Microsoft.AspNetCore.Mvc.ViewEngines;
    using Microsoft.AspNetCore.Mvc.ViewFeatures;
    using Microsoft.AspNetCore.Routing;
    using System;
    using System.IO;
    using System.Linq;
    using System.Threading.Tasks;

    public sealed class RazorViewToStringRenderer : IRazorViewToStringRenderer
    {
        private readonly IRazorViewEngine _viewEngine;
        private readonly ITempDataProvider _tempDataProvider;
        private readonly IServiceProvider _serviceProvider;

        public RazorViewToStringRenderer(
            IRazorViewEngine viewEngine,
            ITempDataProvider tempDataProvider,
            IServiceProvider serviceProvider)
        {
            _viewEngine = viewEngine;
            _tempDataProvider = tempDataProvider;
            _serviceProvider = serviceProvider;
        }

        public async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model)
        {
           //If you wish to use the route data in the generated view (e.g. use 
           //the Url helper to construct dynamic links)
           //inject the IHttpContextAccessor then use: var actionContext = new ActionContext(_contextAccessor.HttpContext, _contextAccessor.HttpContext.GetRouteData(), new ActionDescriptor());
          //instead of the line below

            var actionContext = GetActionContext();
            var view = FindView(actionContext, viewName);

            using (var output = new StringWriter())
            {
                var viewContext = new ViewContext(
                    actionContext,
                    view,
                    new ViewDataDictionary<TModel>(
                        metadataProvider: new EmptyModelMetadataProvider(),
                        modelState: new ModelStateDictionary())
                    {
                        Model = model
                    },
                    new TempDataDictionary(
                        actionContext.HttpContext,
                        _tempDataProvider),
                    output,
                    new HtmlHelperOptions());

                await view.RenderAsync(viewContext);

                return output.ToString();
            }
        }

        private IView FindView(ActionContext actionContext, string viewName)
        {
            var getViewResult = _viewEngine.GetView(executingFilePath: null, viewPath: viewName, isMainPage: true);
            if (getViewResult.Success)
            {
                return getViewResult.View;
            }

            var findViewResult = _viewEngine.FindView(actionContext, viewName, isMainPage: true);
            if (findViewResult.Success)
            {
                return findViewResult.View;
            }

            var searchedLocations = getViewResult.SearchedLocations.Concat(findViewResult.SearchedLocations);
            var errorMessage = string.Join(
                Environment.NewLine,
                new[] { $"Unable to find view '{viewName}'. The following locations were searched:" }.Concat(searchedLocations)); ;

            throw new InvalidOperationException(errorMessage);
        }

        private ActionContext GetActionContext()
        {
            var httpContext = new DefaultHttpContext();
            httpContext.RequestServices = _serviceProvider;
            return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
        }
    }

    public interface IRazorViewToStringRenderer
    {
        Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model);
    }

Run Code Online (Sandbox Code Playgroud)

  • 可悲的是,这个评论对我来说只说了一半。虽然此代码实际完成了将 razor 页面转换为 html 字符串的工作,但周围的设置必须适合,否则编译器会抱怨。确保将 `services.AddControllersWithViews();` 和 `services.AddRazorPages();` 添加到 Startup.cs 中。确保在下面正确添加 DI:`services.AddTransient&lt;IRazorViewToStringRenderer, RazorViewToStringRenderer&gt;();` 并确保您的项目位于 .Net Core 3.1 上。我感觉这在 .net core 3 上工作有问题。如果我错了,请纠正我。希望这对一些人有帮助1 (2认同)

Pha*_*lon 10

Red的回答使我有99%的解决方法,但是如果您的视图位于意外位置,则无法使用。这是我的解决办法。

using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System.IO;
using System.Threading.Tasks;

namespace Example
{
    public static class ControllerExtensions
    {
        public static async Task<string> RenderViewAsync<TModel>(this Controller controller, string viewName, TModel model, bool isPartial = false)
        {
            if (string.IsNullOrEmpty(viewName))
            {
                viewName = controller.ControllerContext.ActionDescriptor.ActionName;
            }

            controller.ViewData.Model = model;

            using (var writer = new StringWriter())
            {
                IViewEngine viewEngine = controller.HttpContext.RequestServices.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
                ViewEngineResult viewResult = GetViewEngineResult(controller, viewName, isPartial, viewEngine);

                if (viewResult.Success == false)
                {
                    throw new System.Exception($"A view with the name {viewName} could not be found");
                }

                ViewContext viewContext = new ViewContext(
                    controller.ControllerContext,
                    viewResult.View,
                    controller.ViewData,
                    controller.TempData,
                    writer,
                    new HtmlHelperOptions()
                );

                await viewResult.View.RenderAsync(viewContext);

                return writer.GetStringBuilder().ToString();
            }
        }

        private static ViewEngineResult GetViewEngineResult(Controller controller, string viewName, bool isPartial, IViewEngine viewEngine)
        {
            if (viewName.StartsWith("~/"))
            {
                var hostingEnv = controller.HttpContext.RequestServices.GetService(typeof(IHostingEnvironment)) as IHostingEnvironment;
                return viewEngine.GetView(hostingEnv.WebRootPath, viewName, !isPartial);
            }
            else
            {
                return viewEngine.FindView(controller.ControllerContext, viewName, !isPartial);

            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这使您可以如下使用它:

var emailBody = await this.RenderViewAsync("~/My/Different/View.cshtml", myModel);
Run Code Online (Sandbox Code Playgroud)

  • 有效,但“IHostingEnvironment”已过时。只需替换为“IWebHostEnvironment”即可。 (4认同)
  • 这个答案有一个问题,因为它改变了控制器自己的模型“controller.ViewData.Model = model;”,我们必须撤消任何更改,否则会破坏后续视图渲染。我将这个突变和渲染封装在 try-finally 中来修复它。 (3认同)

Mah*_*san 10

.NET 5

这里已经发布了很多很棒的答案。基本上我遇到了类似的问题,我想从 razor (.cshtml) 页面读取电子邮件模板作为字符串,我遇到了这个问题并尝试了所有答案。我在 .NET 5 中遇到了一些问题,因此我在这里发布了稍微调整过的解决方案。谢谢。

Startup.cs文件

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddScoped<CustomViewRendererService>();
    ...
}
Run Code Online (Sandbox Code Playgroud)

CustomViewRendererService.cs文件

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System;
using System.IO;
using System.Threading.Tasks;

namespace Services
{
    public class CustomViewRendererService
    {
        private readonly IRazorViewEngine _razorViewEngine;
        private readonly ITempDataProvider _tempDataProvider;

        public CustomViewRendererService(
            IRazorViewEngine razorViewEngine,
            ITempDataProvider tempDataProvider)
        {
            _razorViewEngine = razorViewEngine;
            _tempDataProvider = tempDataProvider;
        }
        
        public async Task<string> RenderViewToStringAsync(ControllerContext actionContext, string viewPath, object model)
        {
            var viewEngineResult = _razorViewEngine.GetView(viewPath, viewPath, false);

            if (viewEngineResult.View == null || (!viewEngineResult.Success))
            {
                throw new ArgumentNullException($"Unable to find view '{viewPath}'");
            }

            var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), actionContext.ModelState);
            viewDictionary.Model = model;

            var view = viewEngineResult.View;
            var tempData = new TempDataDictionary(actionContext.HttpContext, _tempDataProvider);

            using var sw = new StringWriter();
            var viewContext = new ViewContext(actionContext, view, viewDictionary, tempData, sw, new HtmlHelperOptions());
            await view.RenderAsync(viewContext);
            return sw.ToString();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的控制器中

public class TestController : ControllerBase
{
    private readonly CustomViewRendererService _viewService;

    public TestController(CustomViewRendererService viewService)
    {
        _viewService = viewService;
    }

    public async Task<IActionResult> SendTestEmail2Async()
    {
        var templatePath = "~/Views/Email/Test.cshtml";
        var msg = await _viewService.RenderViewToStringAsync(ControllerContext, templatePath, ("Foo", "Bar"));
        
        return Ok(msg);
    }
}
Run Code Online (Sandbox Code Playgroud)

最后Test.cshtml归档

@model (string arg1, string arg2)

<h1>Param: @Model.arg1</h1>
<h1>Param @Model.arg2</h1>
Run Code Online (Sandbox Code Playgroud)


Dav*_*row 5

上面的答案很好,但需要进行调整才能使任何标签助手工作(我们需要使用实际的 http 上下文)。此外,您还需要在视图中显式设置布局才能呈现布局。

public class ViewRenderService : IViewRenderService
{
    private readonly IRazorViewEngine _razorViewEngine;
    private readonly ITempDataProvider _tempDataProvider;
    private readonly IServiceProvider _serviceProvider;
    private readonly IHostingEnvironment _env;
    private readonly HttpContext _http;

    public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider, IHostingEnvironment env, IHttpContextAccessor ctx)
    {
        _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; _env = env; _http = ctx.HttpContext;
    }

    public async Task<string> RenderToStringAsync(string viewName, object model)
    {
        var actionContext = new ActionContext(_http, new RouteData(), new ActionDescriptor());

        using (var sw = new StringWriter())
        {
            var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
            //var viewResult = _razorViewEngine.GetView(_env.WebRootPath, viewName, false); // For views outside the usual Views folder
            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(_http, _tempDataProvider), sw, new HtmlHelperOptions());
            viewContext.RouteData = _http.GetRouteData();
            await viewResult.View.RenderAsync(viewContext);
            return sw.ToString();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 注意:在 azure 上,我需要将以下内容添加到 Startup `services.AddSingleton&lt;IHttpContextAccessor, HttpContextAccessor&gt;(); ` 在没有这个的情况下,在本地工作得很好...... (2认同)

Mla*_* B. 5

我可能迟到了,但我设法找到了一种解决方案,该解决方案无需实例化新的视图引擎( RazorViewEngine ),而是实际重用每个控制器中已有的视图引擎。此外,通过这种方法,我们还可以在键入视图名称时从IntelliSense获得帮助,这在尝试确定确切的视图路径时非常有用。

因此,使用这种方法,您的代码将如下所示:

public override async Task<IActionResult> SignUp()
{
    ...
    // send an email notification
    var emailView = View("Emails/SignupNotification"); // simply get the email view
    var emailBody = await RenderToStringAsync(emailView, _serviceProvider); // render it as a string

    SendEmail(emailBody);
    ...

    return View();
}
Run Code Online (Sandbox Code Playgroud)

RenderToStringAsync本示例中使用的方法如下所示:

private static async Task<string> RenderToStringAsync(ViewResult viewResult, IServiceProvider serviceProvider)
{
    if (viewResult == null) throw new ArgumentNullException(nameof(viewResult));

    var httpContext = new DefaultHttpContext
    {
        RequestServices = serviceProvider
    };

    var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

    using (var stream = new MemoryStream())
    {
        httpContext.Response.Body = stream; // inject a convenient memory stream
        await viewResult.ExecuteResultAsync(actionContext); // execute view result on that stream

        httpContext.Response.Body.Position = 0;
        return new StreamReader(httpContext.Response.Body).ReadToEnd(); // collect the content of the stream
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您将该方法实现为扩展方法,则您的用法可以变成:

public override async Task<IActionResult> SignUp()
{
    ...
    var emailBody = View("Emails/SignupNotification")
        .RenderToStringAsync(_serviceProvider);
    ...

    return View();
}
Run Code Online (Sandbox Code Playgroud)