ASP.NET Web Formsで複数行TextBoxの内容をDBに保存し、次画面で表示したら改行が消えて1行に詰まってしまう——これはWebの「仕様」を知らないとハマりやすい落とし穴です。本記事では原因を整理したうえで、改行を“入力時の見た目のまま”表示する定番2パターン(<br>変換/CSS対応)と、安全に実装するポイントを解説します。
よくある症状:DBには入っているのに、表示すると改行が消える
ASP.NET Web Forms の <asp:TextBox TextMode="MultiLine"> に、次のように行ごとに情報を入力して保存するケースを想定します。
| TextBox入力(ユーザーが見ている形) | DBに保存されている実体 | 次画面でLabel/Literalに表示した結果 |
|---|---|---|
| Name: My Inc. Account: 123456 Account Type: Newbie Station: Media Team | 「Name: My Inc.\r\nAccount: 123456\r\nAccount Type: …」 | Name: My Inc.Account: 123456Account Type: …(1行に連結) |
「DBに改行が入っているなら、そのまま改行表示されるはず」と考えがちですが、Web表示では別のルールが働きます。
原因:HTMLは“改行文字”を見た目の改行として扱わない
DBに保存される改行は、多くの場合 Windows の改行コードである \r\n(CRLF)です。ところがブラウザは、HTML上のテキストに含まれる改行文字をそのまま表示上の改行にはしません。既定のCSS(white-space: normal;)では、空白や改行は「折りたたまれて」1つの空白扱いになり、結果として1行に詰まって見えます。
この挙動を理解するために、HTML/CSS側での扱いを整理します。
| 入力文字 | ブラウザの既定(white-space: normal) | 改行を表示に反映するには |
|---|---|---|
| 半角スペースの連続 | 1つの空白に折りたたまれる | CSSで pre / pre-wrap 等を使う |
| 改行(\r\n や \n) | 空白扱いで折りたたまれる(見た目の改行にならない) | <br /> を挿入する/white-spaceを変更する |
つまり、Webフォームで「改行込みの文字列」をそのまま見た目に反映したいなら、HTMLに改行を表現する仕掛けを追加する必要があります。
解決策は2系統:<br /> 変換か、CSS(white-space)か
やり方は大きく次の2つです。どちらも「TextBoxは1つ、表示も1つ」という条件で成立します。
| 方法 | 概要 | メリット | 注意点 | 向いている場面 |
|---|---|---|---|---|
| 方法A:改行を<br />に置換 | 文字列中の改行をHTMLの改行タグに変換して出力する | どの要素でも確実に改行表示できる/見た目が安定 | XSS対策として「エンコード→改行置換」の順序が重要 | 表示の確実性を優先したい/メール文面・備考欄など |
| 方法B:CSSで改行を活かす | white-space指定で改行文字を改行として表示させる | DBの値を加工しない/コピー&ペースト時も自然 | CSSが当たっていないと効かない/表示要素のスタイルに依存 | プレーンテキストとして保持したい/HTMLを混ぜたくない |
どちらを選んでもよいのですが、セキュリティ(XSS)を踏まえると実装順序がかなり重要です。ここからはそれぞれを具体例付きで解説します。
方法A:改行(\r\n)を <br /> に変換して表示する(定番)
実装のポイントは「HTMLエンコード→改行を<br/>化」
ユーザー入力をDBに保存している以上、表示時にはスクリプト混入(XSS)を警戒する必要があります。安全に出す基本は「出力時エンコード」です。
ただし、改行を<br />にする場合に順序を間違えると、次のような失敗が起きます。
| やり方 | 結果 | 問題点 |
|---|---|---|
| 改行→<br />置換してからHtmlEncode | <br /> と表示され、改行にならない | エンコードでタグが無害化されるため |
| HtmlEncodeせずに改行→<br />置換 | 改行は表示できる | 入力に<script>等が混入すると実行される危険 |
| HtmlEncodeしてから改行→<br />置換 | 安全に改行も表示できる | 推奨 |
(推奨)LiteralでPassThroughを使う例
Web Formsでは asp:Literal が扱いやすいです。Mode="PassThrough" にすることで、こちらが入れた <br /> をHTMLとして解釈させられます。
ASPX(表示側)
<asp:Literal ID="DetailLiteral" runat="server" Mode="PassThrough" />
C#(表示処理)
var text = dr["details"]?.ToString() ?? "";
// ① まずHTMLエンコードしてスクリプト混入を防ぐ
var encoded = Server.HtmlEncode(text);
// ② エンコード後に改行だけ
に変換する
DetailLiteral.Text = encoded.Replace("\r\n", "
");
DBの改行が必ず \r\n とは限りません。コピー&ペーストや外部連携で \n だけが入ることもあります。その場合は正規化してから置換すると安心です。
改行コードが混在する場合の“強い”変換
static string NewlineToBr(string input)
{
if (input == null) return "";
// 1) まず全部 \n に寄せる(\r\n, \r, \n を統一)
var normalized = input.Replace("\r\n", "\n").Replace("\r", "\n");
// 2) HTMLエンコード
var encoded = System.Web.HttpUtility.HtmlEncode(normalized);
// 3) 改行だけ <br />
return encoded.Replace("\n", "<br />");
}
// 使い方
DetailLiteral.Mode = LiteralMode.PassThrough;
DetailLiteral.Text = NewlineToBr(dr["details"]?.ToString());
Labelで表示する場合の注意
asp:Label は最終的に <span> としてレンダリングされ、Text の内容がそのままHTMLとして出力されます。つまり、エンコードせずにユーザー入力を突っ込むとXSSの危険があります。
Labelで<br/>を出すなら、Literalと同様に「エンコード→改行置換」を徹底してください。
<asp:Label ID="LabelDetail" runat="server" />
var text = dr["details"]?.ToString() ?? "";
var encoded = Server.HtmlEncode(text);
LabelDetail.Text = encoded.Replace("\r\n", "<br />");
ただし、LabelはHTMLとして解釈する前提になりやすいため、チーム開発では「表示はLiteralに寄せる」「Encode/PassThroughの意図をコードに残す」など、事故を防ぐ運用も有効です。
方法B:CSSで改行を活かす(<br/>を埋め込まない)
HTMLに<br/>を混ぜず、文字列はプレーンテキストのまま保持し、表示側のCSSで改行を“見た目の改行”にする方法です。代表が white-space: pre-line; です。
white-space の違いを押さえる
white-spaceは見た目に直結するため、用途に合ったものを選びます。
| 指定 | 改行 | 連続スペース | 主な用途 |
|---|---|---|---|
| normal(既定) | 折りたたむ | 折りたたむ | 通常の文章 |
| pre-line | 保持する | 折りたたむ | 改行だけ活かしたい備考欄 |
| pre-wrap | 保持する | 保持する | 整形済みテキスト(スペースも意味がある) |
| pre | 保持する | 保持する | コードやログ(折り返しさせたくない場合) |
LabelにCSSを当てる例(おすすめはCssClass)
style属性で直書きでも良いですが、運用を考えるとCSSクラスのほうが管理しやすいです。
ASPX(表示側)
<asp:Label ID="LabelDetail" runat="server" CssClass="preserve-newline" />
CSS(例:Site.cssなど)
.preserve-newline{
white-space: pre-line;
}
C#(表示処理)
var text = dr["details"]?.ToString() ?? "";
// HTMLは混ぜないのでエンコードだけでOK
LabelDetail.Text = Server.HtmlEncode(text);
この方法の利点は「DBに保存された文字列がそのまま出る」ことです。たとえばユーザーが表示内容をコピーして別システムへ貼り付ける場合、<br/>を混ぜるより自然なテキストとして扱えます。
Literalでも同様に使える
Literalを使う場合は、ModeをEncodeにしておくと安全面で意図が明確になります(ただし、EncodeはHTMLタグを解釈しません)。
<asp:Literal ID="DetailLiteral" runat="server" Mode="Encode" />
DetailLiteral.Text = dr["details"]?.ToString() ?? "";
そのうえで、Literalが出力する要素(通常はテキストノード)がCSSの対象になるよう、親要素にクラスを付けたり、Literalを囲むコンテナを用意します。
実務で迷わない選び方:表示の安定性か、データの純度か
現場でよくある判断基準をまとめます。
- とにかく表示を崩したくない/HTMLやCSSの影響を受けたくない:方法A(<br/>変換)
- 値はプレーンテキストのまま扱いたい/コピー時に綺麗にしたい:方法B(white-space)
- ログや整形済みテキストでスペースも意味がある:方法Bで
pre-wrapを検討
「どちらが正解」というより、表示要件と運用(コピー、検索、編集、将来の再利用)で決めるのが失敗しません。
DB保存側の注意点:改行の正規化と“HTMLを保存しない”方針
改行問題の対処は表示側で完結できますが、保存側も少し整えておくと後々ラクになります。
改行コードを統一して保存する
Windows由来の入力は通常 \r\n ですが、外部連携やAPI経由で \n のみが混ざることがあります。保存前に統一しておくと、検索や比較が安定します。
var input = TextBox1.Text ?? "";
// DBには \n で統一して保存する例
var normalized = input.Replace("\r\n", "\n").Replace("\r", "\n");
この方針にすると、表示時の変換も \n だけを見ればよくなります(方法Aでも方法Bでも扱いやすい)。
DBには<br/>などのHTMLを入れない
「保存時に改行を<br/>にしてしまえば表示は簡単」と考えることもありますが、将来的に次の問題が起きやすくなります。
- 別画面でプレーンテキストとして使いたいときにHTML除去が必要
- 検索・置換がやりづらい(タグ混在でノイズが増える)
- HTMLの仕様変更(<br>と<br />など)や表示先の違いに引きずられる
基本は「DBには生のテキスト、表示で整形」が安全で再利用しやすい設計です。
よくあるつまずきチェックリスト
実装しても期待通りに改行されない場合は、次を順に確認すると切り分けが早いです。
| 症状 | 原因候補 | 対処 |
|---|---|---|
| <br /> が文字として表示される | HtmlEncodeの順序が逆/LiteralがEncodeモード | 「エンコード→改行置換」/LiteralはPassThroughに |
| 改行が効かない(CSS方式) | white-spaceが当たっていない/別CSSで上書き | CssClassの付与と検証ツールでスタイル確認 |
| 一部だけ改行されない | \n と \r\n が混在 | 正規化してから置換する |
| 画面はOKだがセキュリティが不安 | ユーザー入力の未エンコード出力 | 必ず出力時に HtmlEncode(またはEncodeモード) |
補足:項目が“意味を持つ”なら、カラム分割(正規化)が長期的に強い
今回の例は「Name」「Account」「Account Type」など、明確な項目名と値の組み合わせです。この場合、1カラムにまとめて保存すると、後から次のような要求が出たときに苦労しがちです。
- Account だけで検索したい
- Account Type の入力チェック(Newbie以外を弾く等)をしたい
- 表示順やラベル表記を画面ごとに変えたい
可能なら、DBは項目ごとに分けて保存し、表示時に整形するほうが保守性が上がります。たとえば次のようなイメージです。
| カラム | 例 | 得られるメリット |
|---|---|---|
| Name | My Inc. | 必須チェック、文字数制限、検索が簡単 |
| Account | 123456 | 数値/桁数検証、部分一致検索、重複チェックが容易 |
| AccountType | Newbie | 候補固定(マスタ化)しやすい |
| Station | Media Team | 表示名変更や多言語対応がしやすい |
ただし、既存設計の都合で「1カラムの備考欄にまとめたい」という要件も現実的にあります。その場合でも、この記事の方法A/Bで“見た目の改行”は問題なく再現できます。
まとめ:改行は“データ”ではなく“表示”で扱うのがコツ
- DBに改行(\r\n)が入っていても、HTMLは既定で改行表示しない
- 確実に改行したいなら「HtmlEncode→改行を<br/>化(Literal PassThrough)」が定番
- HTMLを混ぜたくないならCSSの
white-space: pre-line;が手軽 - ユーザー入力を出すなら、どの方法でもXSS対策(出力時エンコード)を最優先にする

コメント