The .NET 2.0 BCL offers various means to create URL encoded strings. One can use System.Uri or System.UriBuilder to create RFC 2396 compliant URLs, or System.Web.HttpUtiliy.UrlEncode(System.String, System.Text.Encoding) to URL encode individual strings. Unfortunately, neither System.Uri nor System.UriBuilder allow one to specify a character encoding for URL encoding. Both classes use UTF-8 exclusively. System.Uri is nonetheless capable of representing URIs whose query strings are based on encodings other than UTF-8, if the user creates a System.Uri from an already URL encoded string. System.Web.HttpUtiliy.UrlEncode(System.String, System.Text.Encoding) on the other hand cannot encode entire query strings, only individual names or values, so a developer must parse query string and encode each name or value individually.
1: using System;
2: using System.Collections.Specialized;
3: using System.Text;
4: using System.Web;
5:
6: namespace JoergJooss.SharpAgent.Http
7: {
8: /// <summary>
9: /// Provides URL encoding capabilities for <see cref="System.Uri"/> and
10: /// <see cref="System.String"/> using arbitrary character encodings.
11: /// </summary>
12: /// <remarks>
13: /// <para>
14: /// The .NET BCL offers various means to create URL encoded strings
15: /// or URI objects with query strings. One can use <see cref="System.Uri"/> or
16: /// <see cref="System.UriBuilder"/> to create RFC 2396 compliant
17: /// URLs, or <see cref="System.Web.HttpUtiliy.UrlEncode(System.String, System.Text.Encoding)"/>
18: /// to URL encode individual strings. Unfortunately, neither
19: /// <see cref="System.Uri"/> nor <see cref="System.UriBuilder"/> allow one
20: /// to specify a character encoding for URL encoding. Both classes use
21: /// UTF-8 exclusively. <see cref="System.Uri"/> is nonetheless capable
22: /// of representing URIs whose query strings are based on encodings
23: /// other than UTF-8, if the user creates a <see cref="System.Uri"/> from
24: /// an already URL encoded string.
25: /// <see cref="System.Web.HttpUtiliy.UrlEncode(System.String, System.Text.Encoding)"/>
26: /// on the other hand cannot encode entire query strings, only individual
27: /// names or values. <see cref="JoergJooss.SharpAgent.Http.UrlEncoder"/>
28: /// is able to encode or reencode <see cref="System.Uri"/> and
29: /// <see cref="System.String"/> objects with arbitrary character encodings.
30: /// </para>
31: /// <para>
32: /// <see cref="JoergJooss.SharpAgent.Http.UrlEncoder"/> instances are
33: /// immutable. All non-inherited instance methods are thread safe.
34: /// </para>
35: /// </remarks>
36: public sealed class UrlEncoder
37: {
38: private readonly Encoding encoding;
39:
40: private static readonly UrlEncoder utf8;
41: private static readonly UrlEncoder latin1;
42: private static readonly UrlEncoder latin9;
43:
44: static UrlEncoder()
45: {
46: utf8 = new UrlEncoder(Encoding.UTF8);
47: latin1 = new UrlEncoder(Encoding.GetEncoding(28591));
48: latin9 = new UrlEncoder(Encoding.GetEncoding(28605));
49: }
50:
51: /// <summary>
52: /// Initializes a new instance of the
53: /// <see cref="JoergJooss.SharpAgent.Http.UrlEncoder"/> class
54: /// that uses the specified character encoding.
55: /// </summary>
56: /// <param name="encoding">An encoding.</param>
57: /// <exception cref="System.ArgumentNullException">
58: /// encoding is <c>null</c>.
59: /// </exception>
60: public UrlEncoder(Encoding encoding)
61: {
62: if (encoding == null)
63: {
64: throw new ArgumentNullException("encoding");
65: }
66:
67: this.encoding = encoding;
68: }
69:
70: /// <summary>
71: /// Gets the encoding used by this instance.
72: /// </summary>
73: /// <value>
74: /// A <see cref="System.Text.Encoding"/> object representing the
75: /// character encoding that is used by this instance.
76: /// </value>
77: public Encoding Encoding
78: {
79: get { return encoding; }
80: }
81:
82: /// <summary>
83: /// Gets a <see cref="JoergJooss.SharpAgent.Http.UrlEncoder"/> for the
84: /// Latin 1 (ISO-8859-1) character encoding.
85: /// </summary>
86: public static UrlEncoder Latin1
87: {
88: get { return latin1; }
89: }
90:
91: /// <summary>
92: /// Gets a <see cref="JoergJooss.SharpAgent.Http.UrlEncoder"/> for
93: /// the Latin 9 (ISO-8859-15) character encoding.
94: /// </summary>
95: public static UrlEncoder Latin9
96: {
97: get { return latin9; }
98: }
99:
100: /// <summary>
101: /// Gets a <see cref="JoergJooss.SharpAgent.Http.UrlEncoder"/> for
102: /// the UTF-8 character encoding.
103: /// </summary>
104: public static UrlEncoder Utf8
105: {
106: get { return utf8; }
107: }
108:
109: /// <summary>
110: /// Gets the Base Class Library's default Encoding object
111: /// used by <see cref="System.Uri"/> and
112: /// <see cref="System.UriBuilder"/>.
113: /// </summary>
114: internal static Encoding DefaultUriEncoding
115: {
116: get { return Encoding.UTF8; }
117: }
118:
119: /// <summary>
120: /// Creates a new Uri object from an existing Uri but
121: /// using the UrlEncoder's character encoding.
122: /// </summary>
123: /// <param name="uri">A URI.</param>
124: /// <returns>The URI whose str string is encoded with
125: /// the UrlEncoder's character encoding.</returns>
126: /// <exception cref="System.ArgumentNullException">
127: /// uri is <c>null</c>.
128: /// </exception>
129: public Uri Encode(Uri uri)
130: {
131: if (uri == null)
132: {
133: throw new ArgumentNullException("uri");
134: }
135:
136: UriBuilder ub = new UriBuilder(uri);
137: ub.Query = EncodeString(uri.Query);
138:
139: return ub.Uri;
140: }
141:
142: /// <summary>
143: /// Creates a new Uri object from a string
144: /// using the UrlEncoder's character encoding.
145: /// </summary>
146: /// <param name="uri">A URI.</param>
147: /// <returns>The URI whose str string is encoded with
148: /// the UrlEncoder's character encoding.</returns>
149: /// <exception cref="System.ArgumentNullException">
150: /// uri is <c>null</c>.
151: /// </exception>
152: public Uri Encode(string uri)
153: {
154: return Encode(new Uri(uri));
155: }
156:
157: /// <summary>
158: /// URL encodes a string with the UrlEncoder's encoding.
159: /// </summary>
160: /// <remarks>
161: /// <paramref name="str"/> is URL decoded before it is being
162: /// encoded. This method assumes UTF-8 as original character
163: /// encoding.
164: /// </remarks>
165: /// <param name="str">A string.</param>
166: /// <returns>A URL encoded representation of <paramref name="str"/>
167: /// using the UrlEncoder's encoding.
168: /// </returns>
169: public string EncodeString(string str)
170: {
171: return EncodeString(str, null);
172: }
173:
174: /// <summary>
175: /// URL encodes a (potentially already URL encoded) string
176: /// with the UrlEncoder's encoding.
177: /// </summary>
178: /// <remarks>
179: /// <paramref name="str"/> is URL decoded before it is being
180: /// encoded, using <paramref name="enc"/> as original character
181: /// encoding.
182: /// </remarks>
183: /// <param name="str">A string.</param>
184: /// <param name="enc">The original character encoding. If <c>null</c>
185: /// is passed, UTF-8 is assumed. </param>
186: /// <returns>A URL encoded representation of <paramref name="str"/>
187: /// using the UrlEncoder's encoding.
188: /// </returns>
189: public string EncodeString(string str, Encoding enc)
190: {
191: if (str == null)
192: {
193: throw new ArgumentNullException("uri");
194: }
195:
196: if (str == String.Empty)
197: {
198: return String.Empty;
199: }
200:
201: StringBuilder sb = new StringBuilder(str.Length);
202: NameValueCollection coll = HttpUtility.ParseQueryString(
203: str,
204: enc != null ? enc : DefaultUriEncoding);
205:
206: foreach (string key in coll)
207: {
208: string encodedKey = HttpUtility.UrlEncode(key, Encoding);
209: string encodedValue = HttpUtility.UrlEncode(coll[key], Encoding);
210: sb.AppendFormat("{0}={1}&", encodedKey, encodedValue);
211: }
212:
213: sb.Length -= 1;
214: return sb.ToString();
215: }
216: }
217: }