-
Notifications
You must be signed in to change notification settings - Fork 357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Input Large Text Area #380
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
| ||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.0.31612.314 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InputLargeTextArea", "src\InputLargeTextArea\InputLargeTextArea.csproj", "{D3C10569-1320-4C66-B76B-FC02BDC9010F}" | ||
EndProject | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleServerApp", "SampleServerApp\SampleServerApp.csproj", "{8162C3A5-8054-4647-B597-64A01027EC24}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{D3C10569-1320-4C66-B76B-FC02BDC9010F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{D3C10569-1320-4C66-B76B-FC02BDC9010F}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{D3C10569-1320-4C66-B76B-FC02BDC9010F}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{D3C10569-1320-4C66-B76B-FC02BDC9010F}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{8162C3A5-8054-4647-B597-64A01027EC24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{8162C3A5-8054-4647-B597-64A01027EC24}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{8162C3A5-8054-4647-B597-64A01027EC24}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{8162C3A5-8054-4647-B597-64A01027EC24}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {130EF2A6-BAD0-430B-9B31-D35406A46F67} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
## Blazor `InputLargeTextArea` Component Sample | ||
A multiline input component for Blazor Server to enable editing large string values. Supports async content access without binding and without validations. | ||
|
||
### Example: | ||
```csharp | ||
<InputLargeTextArea id="largeTextArea" @ref="TextArea" OnChange="TextAreaChanged" /> | ||
|
||
|
||
@code { | ||
InputLargeTextArea? TextArea; | ||
|
||
public async Task GetTextAsync() | ||
{ | ||
var streamReader = await TextArea!.GetTextAsync(maxLength: 50_000); | ||
var textFromInputLargeTextArea = await streamReader.ReadToEndAsync(); | ||
} | ||
|
||
public async Task SetTextAsync() | ||
{ | ||
var textToWrite = new string('c', 50_000); | ||
|
||
var memoryStream = new MemoryStream(); | ||
var streamWriter = new StreamWriter(memoryStream); | ||
await streamWriter.WriteAsync(textToWrite); | ||
await streamWriter.FlushAsync(); | ||
await TextArea!.SetTextAsync(streamWriter); | ||
} | ||
|
||
public void TextAreaChanged(InputLargeTextAreaChangeEventArgs args) | ||
{ | ||
LastChangedLength = args.Length; | ||
} | ||
} | ||
``` | ||
|
||
## Why? | ||
Using Blazor Server's `InputTextArea` with large (ex. 20K chars) amounts of text can lead to a degraded user experience due to the constant round-trip communication to/from the server to enable binding and validations. This component provides an asynchronous ability to get & set the text area content. This approach **is not optimal** due to the additional complexity working with `StreamReader`/`StreamWriter` APIs, as well as the (large) amount of memory allocations which may occur when encoding/decoding the `UTF-8` `string`/`textarea` content into `byte`s. Due to these concerns, we've made this available as a sample instead of adding it to the core framework. | ||
|
||
Note: If you're encountering slowdowns specifically in complex components or Blazor WebAssembly, we recommend reviewing the [Blazor WebAssembly Performance Best Practices](https://docs.microsoft.com/en-us/aspnet/core/blazor/webassembly-performance-best-practices?view=aspnetcore-6.0#avoid-rerendering-after-handling-events-without-state-changes) which detail rendering optimizations. | ||
|
||
## Setup | ||
1. Add a package reference to `InputLargeTextArea`. | ||
2. Add `<script src="_content/InputLargeTextArea/js/InputLargeTextArea.js"></script>` to your `_Layout.cshtml` on Blazor Server. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<Router AppAssembly="@typeof(App).Assembly"> | ||
<Found Context="routeData"> | ||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> | ||
<FocusOnNavigate RouteData="@routeData" Selector="h1" /> | ||
</Found> | ||
<NotFound> | ||
<PageTitle>Not found</PageTitle> | ||
<LayoutView Layout="@typeof(MainLayout)"> | ||
<p role="alert">Sorry, there's nothing at this address.</p> | ||
</LayoutView> | ||
</NotFound> | ||
</Router> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
@page | ||
@model SampleServerApp.Pages.ErrorModel | ||
|
||
<!DOCTYPE html> | ||
<html> | ||
|
||
<head> | ||
<meta charset="utf-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> | ||
<title>Error</title> | ||
<link href="~/css/bootstrap/bootstrap.min.css" rel="stylesheet" /> | ||
<link href="~/css/site.css" rel="stylesheet" asp-append-version="true" /> | ||
</head> | ||
|
||
<body> | ||
<div class="main"> | ||
<div class="content px-4"> | ||
<h1 class="text-danger">Error.</h1> | ||
<h2 class="text-danger">An error occurred while processing your request.</h2> | ||
|
||
@if (Model.ShowRequestId) | ||
{ | ||
<p> | ||
<strong>Request ID:</strong> <code>@Model.RequestId</code> | ||
</p> | ||
} | ||
|
||
<h3>Development Mode</h3> | ||
<p> | ||
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred. | ||
</p> | ||
<p> | ||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong> | ||
It can result in displaying sensitive information from exceptions to end users. | ||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong> | ||
and restarting the app. | ||
</p> | ||
</div> | ||
</div> | ||
</body> | ||
|
||
</html> |
26 changes: 26 additions & 0 deletions
26
src/InputLargeTextArea/SampleServerApp/Pages/Error.cshtml.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using System.Diagnostics; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.AspNetCore.Mvc.RazorPages; | ||
|
||
namespace SampleServerApp.Pages; | ||
|
||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] | ||
[IgnoreAntiforgeryToken] | ||
public class ErrorModel : PageModel | ||
{ | ||
public string? RequestId { get; set; } | ||
|
||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); | ||
|
||
private readonly ILogger<ErrorModel> _logger; | ||
|
||
public ErrorModel(ILogger<ErrorModel> logger) | ||
{ | ||
_logger = logger; | ||
} | ||
|
||
public void OnGet() | ||
{ | ||
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
@page "/" | ||
@using Microsoft.AspNetCore.Components.Forms | ||
|
||
<PageTitle>Input Large Text Area</PageTitle> | ||
|
||
<InputLargeTextArea id="largeTextArea" @ref="TextArea" OnChange="TextAreaChanged" /> | ||
|
||
<br /> | ||
|
||
<button id="setTextBtn" @onclick="SetTextAsync">SetTextAsync</button> | ||
<button id="getTextBtn" @onclick="GetTextAsync">GetTextAsync</button> | ||
|
||
<hr /> | ||
|
||
<h3>Last Changed:</h3> | ||
Length: <p id="lastChangedLength">@LastChangedLength</p> | ||
|
||
<h3>Get Text Result:</h3> | ||
<p id="getTextResult">@GetTextResult</p> | ||
<p id="getTextError">@GetTextError</p> | ||
|
||
|
||
@code { | ||
public long LastChangedLength { get; set; } | ||
public string GetTextResult { get; set; } = string.Empty; | ||
public string GetTextError { get; set; } = string.Empty; | ||
|
||
InputLargeTextArea? TextArea; | ||
|
||
public async Task GetTextAsync() | ||
{ | ||
var streamReader = await TextArea!.GetTextAsync(maxLength: 50_000); | ||
GetTextResult = await streamReader.ReadToEndAsync(); | ||
StateHasChanged(); | ||
} | ||
|
||
public async Task SetTextAsync() | ||
{ | ||
var memoryStream = new MemoryStream(); | ||
var streamWriter = new StreamWriter(memoryStream); | ||
await streamWriter.WriteAsync(new string('c', 50_000)); | ||
await streamWriter.FlushAsync(); | ||
await TextArea!.SetTextAsync(streamWriter); | ||
} | ||
|
||
public void TextAreaChanged(InputLargeTextAreaChangeEventArgs args) | ||
{ | ||
LastChangedLength = args.Length; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
@page "/" | ||
@namespace SampleServerApp.Pages | ||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers | ||
@{ | ||
Layout = "_Layout"; | ||
} | ||
|
||
<component type="typeof(App)" render-mode="ServerPrerendered" /> |
33 changes: 33 additions & 0 deletions
33
src/InputLargeTextArea/SampleServerApp/Pages/_Layout.cshtml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
@using Microsoft.AspNetCore.Components.Web | ||
@namespace SampleServerApp.Pages | ||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers | ||
|
||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<base href="~/" /> | ||
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" /> | ||
<link href="css/site.css" rel="stylesheet" /> | ||
<link href="SampleServerApp.styles.css" rel="stylesheet" /> | ||
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" /> | ||
</head> | ||
<body> | ||
@RenderBody() | ||
|
||
<div id="blazor-error-ui"> | ||
<environment include="Staging,Production"> | ||
An error has occurred. This application may no longer respond until reloaded. | ||
</environment> | ||
<environment include="Development"> | ||
An unhandled exception has occurred. See browser dev tools for details. | ||
</environment> | ||
<a href="" class="reload">Reload</a> | ||
<a class="dismiss">🗙</a> | ||
</div> | ||
|
||
<script src="_content/InputLargeTextArea/js/InputLargeTextArea.js"></script> | ||
<script src="_framework/blazor.server.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using Microsoft.AspNetCore.Components; | ||
using Microsoft.AspNetCore.Components.Web; | ||
|
||
var builder = WebApplication.CreateBuilder(args); | ||
|
||
// Add services to the container. | ||
builder.Services.AddRazorPages(); | ||
builder.Services.AddServerSideBlazor(); | ||
|
||
var app = builder.Build(); | ||
|
||
// Configure the HTTP request pipeline. | ||
if (!app.Environment.IsDevelopment()) | ||
{ | ||
app.UseExceptionHandler("/Error"); | ||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. | ||
app.UseHsts(); | ||
} | ||
|
||
app.UseHttpsRedirection(); | ||
|
||
app.UseStaticFiles(); | ||
|
||
app.UseRouting(); | ||
|
||
|
||
app.MapBlazorHub(); | ||
app.MapFallbackToPage("/_Host"); | ||
|
||
app.Run(); |
13 changes: 13 additions & 0 deletions
13
src/InputLargeTextArea/SampleServerApp/SampleServerApp.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<Nullable>enable</Nullable> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\src\InputLargeTextArea\InputLargeTextArea.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
19 changes: 19 additions & 0 deletions
19
src/InputLargeTextArea/SampleServerApp/Shared/MainLayout.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
@inherits LayoutComponentBase | ||
|
||
<PageTitle>SampleServerApp</PageTitle> | ||
|
||
<div class="page"> | ||
<div class="sidebar"> | ||
<NavMenu /> | ||
</div> | ||
|
||
<main> | ||
<div class="top-row px-4"> | ||
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a> | ||
</div> | ||
|
||
<article class="content px-4"> | ||
@Body | ||
</article> | ||
</main> | ||
</div> |
70 changes: 70 additions & 0 deletions
70
src/InputLargeTextArea/SampleServerApp/Shared/MainLayout.razor.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
.page { | ||
position: relative; | ||
display: flex; | ||
flex-direction: column; | ||
} | ||
|
||
main { | ||
flex: 1; | ||
} | ||
|
||
.sidebar { | ||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); | ||
} | ||
|
||
.top-row { | ||
background-color: #f7f7f7; | ||
border-bottom: 1px solid #d6d5d5; | ||
justify-content: flex-end; | ||
height: 3.5rem; | ||
display: flex; | ||
align-items: center; | ||
} | ||
|
||
.top-row ::deep a, .top-row .btn-link { | ||
white-space: nowrap; | ||
margin-left: 1.5rem; | ||
} | ||
|
||
.top-row a:first-child { | ||
overflow: hidden; | ||
text-overflow: ellipsis; | ||
} | ||
|
||
@media (max-width: 640.98px) { | ||
.top-row:not(.auth) { | ||
display: none; | ||
} | ||
|
||
.top-row.auth { | ||
justify-content: space-between; | ||
} | ||
|
||
.top-row a, .top-row .btn-link { | ||
margin-left: 0; | ||
} | ||
} | ||
|
||
@media (min-width: 641px) { | ||
.page { | ||
flex-direction: row; | ||
} | ||
|
||
.sidebar { | ||
width: 250px; | ||
height: 100vh; | ||
position: sticky; | ||
top: 0; | ||
} | ||
|
||
.top-row { | ||
position: sticky; | ||
top: 0; | ||
z-index: 1; | ||
} | ||
|
||
.top-row, article { | ||
padding-left: 2rem !important; | ||
padding-right: 1.5rem !important; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasn't sure if I should keep the basic template pages or remove?