109

I'm currently searching for an easy way to serialize objects (in C# 3).

I googled some examples and came up with something like:

MemoryStream memoryStream = new MemoryStream ( );
XmlSerializer xs = new XmlSerializer ( typeof ( MyObject) );
XmlTextWriter xmlTextWriter = new XmlTextWriter ( memoryStream, Encoding.UTF8 );
xs.Serialize ( xmlTextWriter, myObject);
string result = Encoding.UTF8.GetString(memoryStream .ToArray());

After reading this question I asked myself, why not using StringWriter? It seems much easier.

XmlSerializer ser = new XmlSerializer(typeof(MyObject));
StringWriter writer = new StringWriter();
ser.Serialize(writer, myObject);
serializedValue = writer.ToString();

Another Problem was, that the first example generated XML I could not just write into an XML column of SQL Server 2005 DB.

The first question is: Is there a reason why I shouldn't use StringWriter to serialize an Object when I need it as a string afterwards? I never found a result using StringWriter when googling.

The second is, of course: If you should not do it with StringWriter (for whatever reasons), which would be a good and correct way?


Addition:

As it was already mentioned by both answers, I'll further go into the XML to DB problem.

When writing to the Database I got the following exception:

System.Data.SqlClient.SqlException: XML parsing: line 1, character 38, unable to switch the encoding

For string

<?xml version="1.0" encoding="utf-8"?><test/>

I took the string created from the XmlTextWriter and just put as xml there. This one did not work (neither with manual insertion into the DB).

Afterwards I tried manual insertion (just writing INSERT INTO ... ) with encoding="utf-16" which also failed. Removing the encoding totally worked then. After that result I switched back to the StringWriter code and voila - it worked.

Problem: I don't really understand why.

at Christian Hayter: With those tests I'm not sure that I have to use utf-16 to write to the DB. Wouldn't setting the encoding to UTF-16 (in the xml tag) work then?

Solomon Rutzky
  • 46,688
  • 9
  • 128
  • 171
StampedeXV
  • 2,715
  • 2
  • 24
  • 40
  • 1
    I'm going on personal experience. SQL Server only accepts UTF-16, and if you pass it anything else, you are at the mercy of the SQL Server XML parser and its attempts to convert the data. Rather than attempting to find a way of fooling it, I just pass it UTF-16 directly, which will always work. – Christian Hayter Oct 14 '09 at 08:23
  • How are you writing this to the database? Are you passing it a string, or an array of bytes, or writing to a stream? If it's either of the latter two forms, you need to make sure that your declared encoding matches the actual encoding of your binary data. – Jon Skeet Oct 14 '09 at 08:27
  • phew. The manual try I made as Query in the MS SQL Management Studio. The "coded" tries were written to a string which was then passed to an O/R Mapper which writes as a string (as far as I could follow). In fact I'm passing it the string that was created in the two examples given in my question. – StampedeXV Oct 14 '09 at 08:33
  • FYI to readers - near duplicates: http://stackoverflow.com/questions/384974/trying-to-store-xml-content-into-sql-server-2005-fails-encoding-problem and http://stackoverflow.com/questions/3760788/how-to-serialize-object-into-utf-8 – ziesemer Jan 25 '12 at 04:58
  • 1
    I'm changing my accepted answer as I believe it actually answers my question. Even though the other answers were helping me continue my work, for the purpose of Stackoverflow I think Solomon's answer will help others better understand what happened. [Disclaimer]: I didn't find the time to really verify the answer. – StampedeXV Apr 02 '19 at 11:45

7 Answers7

242

One problem with StringWriter is that by default it doesn't let you set the encoding which it advertises - so you can end up with an XML document advertising its encoding as UTF-16, which means you need to encode it as UTF-16 if you write it to a file. I have a small class to help with that though:

public sealed class StringWriterWithEncoding : StringWriter
{
    public override Encoding Encoding { get; }

    public StringWriterWithEncoding (Encoding encoding)
    {
        Encoding = encoding;
    }    
}

Or if you only need UTF-8 (which is all I often need):

public sealed class Utf8StringWriter : StringWriter
{
    public override Encoding Encoding => Encoding.UTF8;
}

As for why you couldn't save your XML to the database - you'll have to give us more details about what happened when you tried, if you want us to be able to diagnose/fix it.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I went into more detail for the database problem now. See question. – StampedeXV Oct 14 '09 at 08:21
  • 4
    Sad the `StringWriter` doesn't take into account the encoding, but never the less, thanks for a nifty little method :) – Chau Apr 12 '11 at 12:40
  • 2
    And "XML parsing: line 1, character 38, unable to switch the encoding" can be solved by "settings.Indent = false; settings.OmitXmlDeclaration = false; " – M.G.E Dec 16 '14 at 03:02
  • I usually get around this by simply using a `MemoryStream` and a `StreamWriter` with the correct encoding. `StreamWriter` *is* a `TextWriter` (the type which `XmlWriter.Create` expects) with customizable encoding, after all. – Nyerguds Jan 14 '15 at 13:02
  • @Nyerguds: Sure, but it's just a bit more work getting the text out afterwards. – Jon Skeet Jan 14 '15 at 13:05
  • @JonSkeet: Not too hard; just `myEncoding.GetString(memstream.GetBuffer());`. And, if it finally does need to be written to a file, `File.WriteAllText(filePath, xmlmessagestr, myEncoding);`. – Nyerguds Jan 14 '15 at 13:21
  • Sure - I'm just saying it's not as convenient as `ToString()` :) It's a fine workaround if you only need it once or twice, but for reusability I'd rather have the classes specified here. – Jon Skeet Jan 14 '15 at 13:23
  • Heh. I guess I just prefer making do with what is there before subclassing things. Relying on toolset classes in different projects / work contexts means you always need to have them with you or recreate them when you need them. – Nyerguds Jan 14 '15 at 13:27
  • 3
    @Nyerguds: So create a Nuget package with this sort of thing, then it's always easy to get at. I'd rather do that than compromise the readability of code which is fundamentally about some other requirement. – Jon Skeet Jan 14 '15 at 13:29
  • @JonSkeet I mean that toolsets I create at work can't be used for my personal projects. Copyrights and all that ;) – Nyerguds Jan 28 '15 at 09:19
  • @Nyerguds so create them as personal projects, under a licence that you can use in your work ;-) - I usually find clients don't object to using an MIT licensed nuget package, in fact I'd be amazed if your commercial projects don't already pull in a bunch of nuget packages. – Tim Abell Jul 19 '16 at 11:43
  • @TimAbell I'm not allowed to work on personal projects at work, though. Anything I write at work belongs to my boss ;) – Nyerguds Jul 25 '16 at 08:52
  • @Nyerguds: So create a NuGet package and host your own NuGet repository at work. If you're saying there's basically *no way* for you to reuse code, you should absolutely complain to your boss. There's simply no reason for that in this day and age. – Jon Skeet Jul 25 '16 at 08:54
  • Beware that this won't work correctly as the resulting string is still UTF-16, whatever encoding you set, not UTF-8. – Softlion May 11 '17 at 11:14
  • @Softlion: Please define "work correctly". I think you may have misunderstood the purpose of the `Encoding` property of `TextWriter`. Given that `StringWriter` doesn't involve bytes *anywhere*, I think it would be clearer to consider it as not applying *any* encoding rather than a string being "in" UTF-16. This solution "works correctly" for the purposes of allowing a `StringWriter` to advertise a particular encoding for other code that uses it. Yes, if you convert the string to binary later on you should make sure you use the right encoding, but that's fine in many cases. – Jon Skeet May 11 '17 at 11:31
  • @Softlion: So in what case do you believe it doesn't "work correctly"? Note that the documentation for `TextWriter.Encoding` specifically points out: "This property is necessary for some XML scenarios where a header must be written containing the encoding used by the TextWriter. This enables the XML code to consume an arbitrary TextWriter and generate the correct XML header." The purpose of this code is to generate an XML header with the specified encoding - so in what way do you justify claiming that "this won't work correctly"? – Jon Skeet May 11 '17 at 13:04
  • Well if the real purpose of this field was what is written, why would it be read only ?Maybe you can try a PR in the .NET Framework with this property set to read/write to validate the whole theory and verify that there is no side case. For now, i assume this is a hack. – Softlion May 11 '17 at 13:12
  • @Softlion: The "theory" that the property's intended purpose is as documented, and that my code works fine to solve the question that was asked? I think there's plenty of evidence already for that "theory" - whereas you have presented **nothing** specific to back up your assertion that "this won't work correctly". I'm still entirely happy with my answer. – Jon Skeet May 11 '17 at 13:24
126

When serialising an XML document to a .NET string, the encoding must be set to UTF-16. Strings are stored as UTF-16 internally, so this is the only encoding that makes sense. If you want to store data in a different encoding, you use a byte array instead.

SQL Server works on a similar principle; any string passed into an xml column must be encoded as UTF-16. SQL Server will reject any string where the XML declaration does not specify UTF-16. If the XML declaration is not present, then the XML standard requires that it default to UTF-8, so SQL Server will reject that as well.

Bearing this in mind, here are some utility methods for doing the conversion.

public static string Serialize<T>(T value) {

    if(value == null) {
        return null;
    }

    XmlSerializer serializer = new XmlSerializer(typeof(T));

    XmlWriterSettings settings = new XmlWriterSettings()
    {
        Encoding = new UnicodeEncoding(false, false), // no BOM in a .NET string
        Indent = false,
        OmitXmlDeclaration = false
    };

    using(StringWriter textWriter = new StringWriter()) {
        using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings)) {
            serializer.Serialize(xmlWriter, value);
        }
        return textWriter.ToString();
    }
}

public static T Deserialize<T>(string xml) {

    if(string.IsNullOrEmpty(xml)) {
        return default(T);
    }

    XmlSerializer serializer = new XmlSerializer(typeof(T));

    XmlReaderSettings settings = new XmlReaderSettings();
    // No settings need modifying here

    using(StringReader textReader = new StringReader(xml)) {
        using(XmlReader xmlReader = XmlReader.Create(textReader, settings)) {
            return (T) serializer.Deserialize(xmlReader);
        }
    }
}
lordnik22
  • 48
  • 1
  • 8
Christian Hayter
  • 30,581
  • 6
  • 72
  • 99
  • See question addition. I don't understand my test results, it _seems_ to contradict your statement that the DB always wants/takes/needs UTF-16. – StampedeXV Oct 14 '09 at 08:21
  • 9
    You *don't* have to encode as UTF-16 - but you have to make sure that the encoding you use matches what the `StringWriter` expects. See my answer. The internal storage format is irrelevant here. – Jon Skeet Oct 14 '09 at 08:26
  • ok that I understand. In my new example: leaving the encoding completely out made the DB decide for itself which encoding was used - thats why it worked. Do I understand it correct now? – StampedeXV Oct 14 '09 at 08:30
  • or as Christian sais: it decides which is used and then converts it to UTF-16 – StampedeXV Oct 14 '09 at 08:41
  • I don't know for sure what heuristics the SQL Server XML parser is using. I would *hope* that it uses the official W3C rules (http://www.w3.org/TR/2000/REC-xml-20001006#sec-guessing-no-ext-info), but it could be doing something else. – Christian Hayter Oct 14 '09 at 08:45
  • I've tried the code, and interestingly, Resharper 5.1 reckons the Serialize is missing a class constraint "where T: Class" and the Deserialize return of null is an error ... "cannot convert null to type parameter T" – SteveC Feb 09 '11 at 14:46
  • 1
    @SteveC: Sorry, my mistake. I hand-converted the code from VB, in which `Nothing` is implicitly convertible to any type. I have corrected the `Deserialize` code. The `Serialize` warning must be a Resharper-only thing, the compiler on its own doesn't object and it is legal to do. – Christian Hayter Feb 09 '11 at 15:43
  • Yeap, went back and it was the blue squiggly of suggestion, rather than the red one from the compiler – SteveC Feb 10 '11 at 17:11
  • 1
    Extending upon Jon Skeet's comment, no, UTF-16 is not required. Please refer to http://stackoverflow.com/a/8998183/751158 for a concrete example demonstrating this. – ziesemer Aug 05 '13 at 15:43
  • This doesn't work in 4.5, throws 'xxxxx was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically' http://stackoverflow.com/questions/11886290/use-the-xmlinclude-or-soapinclude-attribute-to-specify-types-that-are-not-known – Anuj Pandey May 21 '15 at 13:56
  • Christian (and @StampedeXV): I'm not trying to be negative about a clearly well-liked answer (124 votes!), but in the pursuit of truth and not spreading misinformation, I need to point out that this answer is nearly 100% wrong. Yes, it appears to work, but as far as my testing shows, the serialization is nearly identical (outside of no CRLF after the XML declaration) to the O.P.s code (2nd code block). The 1st paragraph (about .NET) is fine. But the 2nd about SQL Server is 100% wrong. Please see [my answer below](https://stackoverflow.com/a/53622960/577765) for details. Continued... – Solomon Rutzky Dec 13 '18 at 19:16
  • (@ziesemer as FYI): "_any string passed into an xml column must be encoded as UTF-16_". No. Only `NVARCHAR` data needs to be UTF-16 LE. `VARCHAR` data (variable/parameter declared as such, or literal string _not_ prefixed with "N") can be any 8-bit encoding. "_SQL Server will reject any string where the XML declaration does not specify UTF-16_". No. This only happens when passing in `NVARCHAR` data. `VARCHAR` data can (and needs to) specify a valid 8-bit encoding, which can be `UTF-8`, or `Windows-1252`, etc. Continued (sorry)... – Solomon Rutzky Dec 13 '18 at 19:25
  • "_If XML declaration is not present, then the XML standard requires that it default to UTF-8, so SQL Server will reject that as well._" No. If the XML declaration is missing, then, if it's a `VARCHAR` string, the encoding is assumed to be the Code Page of the default Collation of the current DB (which couldn't be UTF-8 until SQL Server 2019), else it will be taken as what is specified in the XML declaration, which can be UTF-8 or many others. Else, if it's an `NVARCHAR` string, the encoding is assumed to be UTF-16 (UTF-16 LE, specifically). Please either correct or remove this answer. Thanks. – Solomon Rutzky Dec 13 '18 at 19:31
21

First of all, beware of finding old examples. You've found one that uses XmlTextWriter, which is deprecated as of .NET 2.0. XmlWriter.Create should be used instead.

Here's an example of serializing an object into an XML column:

public void SerializeToXmlColumn(object obj)
{
    using (var outputStream = new MemoryStream())
    {
        using (var writer = XmlWriter.Create(outputStream))
        {
            var serializer = new XmlSerializer(obj.GetType());
            serializer.Serialize(writer, obj);
        }

        outputStream.Position = 0;
        using (var conn = new SqlConnection(Settings.Default.ConnectionString))
        {
            conn.Open();

            const string INSERT_COMMAND = @"INSERT INTO XmlStore (Data) VALUES (@Data)";
            using (var cmd = new SqlCommand(INSERT_COMMAND, conn))
            {
                using (var reader = XmlReader.Create(outputStream))
                {
                    var xml = new SqlXml(reader);

                    cmd.Parameters.Clear();
                    cmd.Parameters.AddWithValue("@Data", xml);
                    cmd.ExecuteNonQuery();
                }
            }
        }
    }
}
John Saunders
  • 160,644
  • 26
  • 247
  • 397
  • 2
    I can only vote this up once, but this deserves to be the top answer here. In the end, it doesn't matter what encoding is declared or used, as long as the `XmlReader` can parse it. It will be sent pre-parsed to the database, and then the DB doesn't need to know anything about character encodings - UTF-16 or otherwise. In particular, note that the XML declarations aren't even persisted with the data in the database, regardless of which method is used to insert it. Please don't make waste by running XML through extra conversions, as shown in other answers here and elsewhere. – ziesemer Jan 25 '12 at 04:57
1
public static T DeserializeFromXml<T>(string xml)
{
    T result;
    XmlSerializerFactory serializerFactory = new XmlSerializerFactory();
    XmlSerializer serializer =serializerFactory.CreateSerializer(typeof(T));

    using (StringReader sr3 = new StringReader(xml))
    {
        XmlReaderSettings settings = new XmlReaderSettings()
        {
            CheckCharacters = false // default value is true;
        };

        using (XmlReader xr3 = XmlTextReader.Create(sr3, settings))
        {
            result = (T)serializer.Deserialize(xr3);
        }
    }

    return result;
}
splash
  • 13,037
  • 1
  • 44
  • 67
1

<TL;DR> The problem is rather simple, actually: you are not matching the declared encoding (in the XML declaration) with the datatype of the input parameter. If you manually added <?xml version="1.0" encoding="utf-8"?><test/> to the string, then declaring the SqlParameter to be of type SqlDbType.Xml or SqlDbType.NVarChar would give you the "unable to switch the encoding" error. Then, when inserting manually via T-SQL, since you switched the declared encoding to be utf-16, you were clearly inserting a VARCHAR string (not prefixed with an upper-case "N", hence an 8-bit encoding, such as UTF-8) and not an NVARCHAR string (prefixed with an upper-case "N", hence the 16-bit UTF-16 LE encoding).

The fix should have been as simple as:

  1. In the first case, when adding the declaration stating encoding="utf-8": simply don't add the XML declaration.
  2. In the second case, when adding the declaration stating encoding="utf-16": either
    1. simply don't add the XML declaration, OR
    2. simply add an "N" to the input parameter type: SqlDbType.NVarChar instead of SqlDbType.VarChar :-) (or possibly even switch to using SqlDbType.Xml)

(Detailed response is below)


All of the answers here are over-complicated and unnecessary (regardless of the 121 and 184 up-votes for Christian's and Jon's answers, respectively). They might provide working code, but none of them actually answer the question. The issue is that nobody truly understood the question, which ultimately is about how the XML datatype in SQL Server works. Nothing against those two clearly intelligent people, but this question has little to nothing to do with serializing to XML. Saving XML data into SQL Server is much easier than what is being implied here.

It doesn't really matter how the XML is produced as long as you follow the rules of how to create XML data in SQL Server. I have a more thorough explanation (including working example code to illustrate the points outlined below) in an answer on this question: How to solve “unable to switch the encoding” error when inserting XML into SQL Server, but the basics are:

  1. The XML declaration is optional
  2. The XML datatype stores strings always as UCS-2 / UTF-16 LE
  3. If your XML is UCS-2 / UTF-16 LE, then you:
    1. pass in the data as either NVARCHAR(MAX) or XML / SqlDbType.NVarChar (maxsize = -1) or SqlDbType.Xml, or if using a string literal then it must be prefixed with an upper-case "N".
    2. if specifying the XML declaration, it must be either "UCS-2" or "UTF-16" (no real difference here)
  4. If your XML is 8-bit encoded (e.g. "UTF-8" / "iso-8859-1" / "Windows-1252"), then you:
    1. need to specify the XML declaration IF the encoding is different than the code page specified by the default Collation of the database
    2. you must pass in the data as VARCHAR(MAX) / SqlDbType.VarChar (maxsize = -1), or if using a string literal then it must not be prefixed with an upper-case "N".
    3. Whatever 8-bit encoding is used, the "encoding" noted in the XML declaration must match the actual encoding of the bytes.
    4. The 8-bit encoding will be converted into UTF-16 LE by the XML datatype

With the points outlined above in mind, and given that strings in .NET are always UTF-16 LE / UCS-2 LE (there is no difference between those in terms of encoding), we can answer your questions:

Is there a reason why I shouldn't use StringWriter to serialize an Object when I need it as a string afterwards?

No, your StringWriter code appears to be just fine (at least I see no issues in my limited testing using the 2nd code block from the question).

Wouldn't setting the encoding to UTF-16 (in the xml tag) work then?

It isn't necessary to provide the XML declaration. When it is missing, the encoding is assumed to be UTF-16 LE if you pass the string into SQL Server as NVARCHAR (i.e. SqlDbType.NVarChar) or XML (i.e. SqlDbType.Xml). The encoding is assumed to be the default 8-bit Code Page if passing in as VARCHAR (i.e. SqlDbType.VarChar). If you have any non-standard-ASCII characters (i.e. values 128 and above) and are passing in as VARCHAR, then you will likely see "?" for BMP characters and "??" for Supplementary Characters as SQL Server will convert the UTF-16 string from .NET into an 8-bit string of the current Database's Code Page before converting it back into UTF-16 / UCS-2. But you shouldn't get any errors.

On the other hand, if you do specify the XML declaration, then you must pass into SQL Server using the matching 8-bit or 16-bit datatype. So if you have a declaration stating that the encoding is either UCS-2 or UTF-16, then you must pass in as SqlDbType.NVarChar or SqlDbType.Xml. Or, if you have a declaration stating that the encoding is one of the 8-bit options (i.e. UTF-8, Windows-1252, iso-8859-1, etc), then you must pass in as SqlDbType.VarChar. Failure to match the declared encoding with the proper 8 or 16 -bit SQL Server datatype will result in the "unable to switch the encoding" error that you were getting.

For example, using your StringWriter-based serialization code, I simply printed the resulting string of the XML and used it in SSMS. As you can see below, the XML declaration is included (because StringWriter does not have an option to OmitXmlDeclaration like XmlWriter does), which poses no problem so long as you pass the string in as the correct SQL Server datatype:

-- Upper-case "N" prefix == NVARCHAR, hence no error:
DECLARE @Xml XML = N'<?xml version="1.0" encoding="utf-16"?>
<string>Test ሴ</string>';
SELECT @Xml;
-- <string>Test ሴ</string>

As you can see, it even handles characters beyond standard ASCII, given that is BMP Code Point U+1234, and is Supplementary Character Code Point U+1F638. However, the following:

-- No upper-case "N" prefix on the string literal, hence VARCHAR:
DECLARE @Xml XML = '<?xml version="1.0" encoding="utf-16"?>
<string>Test ሴ</string>';

results in the following error:

Msg 9402, Level 16, State 1, Line XXXXX
XML parsing: line 1, character 39, unable to switch the encoding

Ergo, all of that explanation aside, the full solution to your original question is:

You were clearly passing the string in as SqlDbType.VarChar. Switch to SqlDbType.NVarChar and it will work without needing to go through the extra step of removing the XML declaration. This is preferred over keeping SqlDbType.VarChar and removing the XML declaration because this solution will prevent data loss when the XML includes non-standard-ASCII characters. For example:

-- No upper-case "N" prefix on the string literal == VARCHAR, and no XML declaration:
DECLARE @Xml2 XML = '<string>Test ሴ</string>';
SELECT @Xml2;
-- <string>Test ???</string>

As you can see, there is no error this time, but now there is data-loss 🙀.

Solomon Rutzky
  • 46,688
  • 9
  • 128
  • 171
  • I think I was the reason for this overcomplicated answers, as I basically had two questions in one. I really like your concise answer and will try it out next time I have to store XML in DB. So if I see this right: you explained the challenges with storing XML to DB. Jon Skeet summarizd issues with using StringWriter when working with XML (except for UTF-16) and Christian Hayter provides a nice way to just work with it. – StampedeXV Dec 07 '18 at 07:34
  • @StampedeXV I updated my answer (a few changes for clarity + new stuff to better illustrate the points). Hopefully it's clearer now that while both of those answers are good on their own, they're not necessary in any way in order to answer your question. They deal with XML serialization in C# / .NET, but this question is really about saving XML in SQL Server. They provide info that is good to know, and might be better code than you originally provided, but neither of them (nor any of the others here), are truly on-topic. But this is not well-documented stuff, hence the confusion. – Solomon Rutzky Dec 07 '18 at 18:22
  • @StampedeXV Did my revisions make sense? I just added a summary section to the top that might be clearer. Long story short: unless there was something else going on that you didn't include details of in the question, then it looks like your code was 99% correct, and probably could have been fixed with the addition of a single upper-case "N". No special encoding stuff is needed, and Christian's code is nice, but my testing shows that it returns serialization identical to your 2nd code block, except yours puts a CRLF after the XML declaration. I bet you changed to `SqlDbType.NVarChar` or `Xml`. – Solomon Rutzky Dec 13 '18 at 19:06
  • still trying to find the time to check it myself. It certainly sounds good and logical, but not sure that would be sufficient to change an accepted answer. – StampedeXV Dec 14 '18 at 10:53
1

For anyone in need of an F# version of the approved answer:

type private Utf8StringWriter() =
    inherit StringWriter()
    override _.Encoding = System.Text.Encoding.UTF8
Johannes Mols
  • 890
  • 1
  • 12
  • 35
-2

It may have been covered elsewhere but simply changing the encoding line of the XML source to 'utf-16' allows the XML to be inserted into a SQL Server 'xml'data type.

using (DataSetTableAdapters.SQSTableAdapter tbl_SQS = new DataSetTableAdapters.SQSTableAdapter())
{
    try
    {
        bodyXML = @"<?xml version="1.0" encoding="UTF-8" standalone="yes"?><test></test>";
        bodyXMLutf16 = bodyXML.Replace("UTF-8", "UTF-16");
        tbl_SQS.Insert(messageID, receiptHandle, md5OfBody, bodyXMLutf16, sourceType);
    }
    catch (System.Data.SqlClient.SqlException ex)
    {
        Console.WriteLine(ex.Message);
        Console.ReadLine();
    }
}

The result is all of the XML text is inserted into the 'xml' data type field but the 'header' line is removed. What you see in the resulting record is just

<test></test>

Using the serialization method described in the "Answered" entry is a way of including the original header in the target field but the result is that the remaining XML text is enclosed in an XML <string></string> tag.

The table adapter in the code is a class automatically built using the Visual Studio 2013 "Add New Data Source: wizard. The five parameters to the Insert method map to fields in a SQL Server table.

DLG
  • 148
  • 3
  • 3
    Seriously - don't do this. Ever. What if I wanted to include some prose in my xml that mentioned "UTF-8" - you've just changed my data to something I didn't say! – Tim Abell Jul 19 '16 at 11:46
  • 3
    Thanks for pointing out a mistake in the code. Rather than bodyXML.Replace("UTF-8", "UTF-16") there should be code that focuses on the XML header changing UTF-8 to UTF-16. What I was really trying to point out is by making this change in the header of the source XML, then the body of the XML can then be inserted into a SQL table record using an XML data type field and the header is stripped off. For reasons I don't recall now (four years ago!) the result was something useful at the time. And yes, dumb mistake using 'Replace'. It happens. – DLG Apr 27 '18 at 14:47