C#におけるURLエンコードとデコードの違いと注意点

### **C#におけるURLエンコードとデコードの違いと注意点**

C#ではURLエンコードやデコードを行う方法として、主に以下の2つのAPIが利用されます：

- **`Uri.EscapeDataString` / `Uri.UnescapeDataString`**
- **`HttpUtility.UrlEncode` / `HttpUtility.UrlDecode`**

これらのAPIは似た役割を持ちますが、それぞれ異なる用途や仕様に基づいて設計されています。本記事では、この2つの違いや使用方法、そして注意点について詳しく解説します。

---

### **1. `Uri.EscapeDataString` / `Uri.UnescapeDataString` の概要**

#### **特徴**
- **URI（Uniform Resource Identifier）全体のエンコード・デコード**に使用します。
- RFC 3986標準に基づいて動作します。
- **スペースは`%20`にエンコード**され、デコード時も`%20`として扱われます。
- **`+`はエンコード対象ではなく、そのまま保持**されます。

#### **使用例**
```csharp
string data = "Hello World+Test";

// エンコード
string encoded = Uri.EscapeDataString(data); // "Hello%20World%2BTest"

// デコード
string decoded = Uri.UnescapeDataString(encoded); // "Hello World+Test"
```

#### **用途**
- URI全体またはその一部（パスやクエリ文字列など）を安全にエンコードする場合に使用します。

---

### **2. `HttpUtility.UrlEncode` / `HttpUtility.UrlDecode` の概要**

#### **特徴**
- **HTTPリクエストやHTMLフォームデータのエンコード・デコード**に特化しています。
- HTMLフォームエンコード仕様（W3C基準）に従います。
- **スペースは`+`にエンコード**され、デコード時に`+`はスペースに戻ります。

#### **使用例**
```csharp
using System.Web;

string data = "Hello World+Test";

// エンコード
string encoded = HttpUtility.UrlEncode(data); // "Hello+World%2bTest"

// デコード
string decoded = HttpUtility.UrlDecode(encoded); // "Hello World+Test"
```

#### **用途**
- クエリ文字列やHTMLフォームのデータを処理する場合に使用します。

---

### **3. 主な違い**

| **特徴**                       | `Uri.EscapeDataString` / `Uri.UnescapeDataString` | `HttpUtility.UrlEncode` / `HttpUtility.UrlDecode` |
|--------------------------------|--------------------------------------------------|---------------------------------------------------|
| **対象仕様**                    | RFC 3986 (URI標準)                              | HTMLフォームエンコード (HTTPリクエスト仕様)       |
| **スペースの扱い**              | `%20`                                           | `+`                                               |
| **`+`の扱い**                   | そのまま保持                                    | エンコード時は`%2B`、デコード時はスペース扱い    |
| **使用場面**                    | URI全体やその一部のエンコード                   | クエリ文字列やフォームデータのエンコード          |
| **依存する名前空間**             | `System`                                        | `System.Web`                                      |

---

### **4. `++`がスペースに変換される問題と対策**

`HttpUtility.UrlDecode`を使用すると、`+`がスペースに変換されることがあります。この仕様により、例えばファイル名に含まれる`++`が正しく処理されず、問題が発生するケースがあります。

#### **問題例**
```csharp
using System.Web;

string encodedFilename = "サンプルファイル1%2B%2B.xlsx";

// デコードすると `++` がスペースに
string decodedFilename = HttpUtility.UrlDecode(encodedFilename); // "サンプルファイル1  .xlsx"
```

#### **対策方法**
1. **デコード後に手動で`+`を復元する**
   ```csharp
   string decodedFilename = HttpUtility.UrlDecode(encodedFilename);
   decodedFilename = decodedFilename.Replace(" ", "+");
   ```

2. **`Uri.UnescapeDataString`を使用する**
   ```csharp
   string decodedFilename = Uri.UnescapeDataString(encodedFilename);
   ```

3. **`+`を事前に`%2B`にエンコードする**
   ```csharp
   string originalFilename = "サンプルファイル1++.xlsx";
   string encodedFilename = Uri.EscapeDataString(originalFilename);
   ```

---

### **5. どちらを選ぶべきか？**

#### **`Uri.EscapeDataString` / `Uri.UnescapeDataString` を選ぶ場合**
- URIそのものをエンコード/デコードする場合。
- 一般的な文字列（例: ファイル名）をURIに安全に含めたい場合。

#### **`HttpUtility.UrlEncode` / `HttpUtility.UrlDecode` を選ぶ場合**
- HTTPリクエストやHTMLフォームのデータをエンコード/デコードする場合。
- Webアプリケーションでクエリ文字列を処理する場合。

---

### **6. 注意点**

1. **`Uri.EscapeDataString`の文字数制限**  
   非常に長い文字列（約32,766文字以上）をエンコードしようとすると`UriFormatException`が発生する可能性があります。

2. **`HttpUtility`の依存性**  
   `HttpUtility`は`System.Web`名前空間に依存しており、.NET Coreや.NET 5以降のプロジェクトでは利用できない場合があります。この場合は`System.Net.WebUtility`を検討してください。

---

### **まとめ**

- **URI全体や一般的なデータを安全にエンコードする場合**は、`Uri.EscapeDataString`を使用します。
- **HTTPリクエストやフォームデータを処理する場合**は、`HttpUtility.UrlEncode`を使用します。
- 問題の状況に応じて適切なAPIを選択し、特定の文字（例: `+`）に関する仕様の違いに注意してください。

この記事が、C#でURLエンコード/デコードを行う際の参考になれば幸いです！