LoginSignup
1
0

More than 5 years have passed since last update.

.NETでサービス参照を使用した場合に、SOAPでCRLFがLFになることへの対策

Last updated at Posted at 2019-02-18

解決したいこと

ClickOnceなどで、Webサービス(asmx)をサービス参照した場合に、改行コードが自動的にCRLFからLFに変わるという問題が発生します。

しかし、そのままでは次のような問題が出てきます。

  • 複数行テキストボックスで改行が反映されない
  • ファイル出力時に改行が反映されない

原因

詳細は検索いただければと思いますが、SOAPの仕様も踏まえ、クライアントまでは正しくたどり着いているが、自動生成されるプロキシクラスでは、既定でCRが消失するという動きとなるようです。

Webメソッドのstring型の戻り値に含まれる改行コードが変換されてしまう

解決方法

WCFを使用しない.NET 2.0までの参照方法であるWeb参照なら、SoapHttpClientProtocolを継承していることもあり、Partialクラスを使用して、スマートに解決できます。

しかし、サービス参照を使用した場合のスマートな解決方法が見つかりませんでした(Partialすべきクラスがわかりませんでした)ので、とりあえずの解決方法を記載します。

もしもっとスマートな解決法があれば、ぜひ教えていただけると助かります!

Webサービス(asmx)をWeb参照した場合(.NET 2.0。.NET 2.0以外では非推奨)

WebMethod中の改行コード(CRLFがLFになっちゃう)

具体的なコードを記載いただいている方がいらっしゃいましたので、上記ページより引用します。

SoapHttpClientProtocol.GetReaderForMessageをオーバーライドすればいい、という情報を得て、
.NET Reflectorで中身を確認したところ、XmlTextReaderのインスタンスをアップキャストして返してるのがわかったので、XmlTextReader.Normalizationをfalseにすることで解決。
コードにしたらこういう感じ。
自動生成のコードには手を入れたくないので、パーシャルクラス様様です。

HogeService.cs
public partial class HogeService
{
    protected override XmlReader GetReaderForMessage(SoapClientMessage message, int bufferSize)
    {
        XmlTextReader reader = (XmlTextReader)base.GetReaderForMessage(message, bufferSize);
        reader.Normalization = false;
        return reader;
    }
}

Webサービス(asmx)をサービス参照した場合(.NET 3.5~)

単純に、Webサービスから取得直後に処理するのみという方法です。

データの処理をクライアント側の使用箇所ごとにで行うため、修正箇所も増え、Document-View(参考1参考2)のアーキテクチャ的にも、本来は望ましくない暫定的な方法です。

SoapNormalization.vb
Public Class SoapNormalization
    Public Shared Sub EditDataSet(inV As DataSet)
        For Each item As DataTable In inV.Tables
            EditDataTable(item)
        Next
    End Sub

    Public Shared Sub EditDataTable(inV As DataTable)
        ' 速度を考慮するなら、String列の判定は1回のみ行う
        inV.AsEnumerable.ToList.ForEach(
            Sub(row)
                For colIndex = 0 To inV.Columns.Count - 1
                    If inV.Columns(colIndex).DataType Is GetType(String) Then
                        ' 文字列のみ処理する
                        row(colIndex) = NormalizeString(row(colIndex))
                    End If
                Next
            End Sub)
    End Sub

    Private Shared Function NormalizeString(v As Object) As Object
        If IsDBNull(v) Then Return v
        If IsNothing(v) Then Return v

        Dim ev = $"{v}"
        ev = ev.Replace(vbLf, vbCrLf)

        Return ev
    End Function
End Class
WebService1.vb
<WebMethod()>
Public Function GetDataSet() As DataSet
    Dim ds = New DataSet("dummy")
    Dim dt = New DataTable

    dt.Columns.Add("c1", GetType(String))
    dt.Columns.Add("c2", GetType(Integer))
    dt.Columns.Add("c3", GetType(Decimal))
    dt.Columns.Add("c4", GetType(Date))

    dt.Rows.Add($"Hello World{vbNewLine}2行目{vbNewLine}3行目{vbNewLine}", 55, 678.9, Now.AddMonths(10))
    dt.Rows.Add($"Hello World", 1, 2.3, DBNull.Value)
    dt.Rows.Add(DBNull.Value, DBNull.Value, DBNull.Value, DBNull.Value)

    dt.TableName = "t1"
    ds.Tables.Add(dt)

    Return ds
End Function
Form1.vb
Dim sv = New WebService1.WebService1SoapClient
Dim ds = sv.GetDataSet

'改行コード対策
SoapNormalization.EditDataSet(ds)

Dim dt = ds.Tables(0)
TextBox1.DataBindings.Add("Text", dt, "c1")
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0