社内ネットワーク環境に最適なCalDAVシステム07:C#からBaïkal(CalDAV)へ予定を登録する

2025年10月30日木曜日

Baikal C# infcloud

t f B! P L

C#からBaïkal(CalDAV)へ予定を登録する

ここでは、C#からCalDAV(Baïkal)サーバーに予定を登録する処理を関数化します。
引数として startDateendDatesubjectdescriptionuri を受け取り、ICalendar形式のデータを送信します。


1. 概要

CalDAVはHTTPベースで動作します。 新しい予定を登録するには、ICS形式(iCalendar) のデータを生成し、 対象カレンダーのURIへ PUTメソッド で送信します。


2. 必要な名前空間


using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

3. 登録関数の実装


public async Task AddCalendarEventAsync(
    DateTime startDate,
    DateTime endDate,
    string subject,
    string description,
    string uri,
    string username,
    string password)
{
    // --- UID(予定を一意に識別) ---
    string uid = Guid.NewGuid().ToString() + "@example.com";

    // --- iCalendar データを生成 ---
    string icsData = $@"BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//YourCompany//CalDAV Client//EN
BEGIN:VEVENT
UID:{uid}
DTSTAMP:{DateTime.UtcNow:yyyyMMddTHHmmssZ}
DTSTART:{startDate:yyyyMMddTHHmmssZ}
DTEND:{endDate:yyyyMMddTHHmmssZ}
SUMMARY:{subject}
DESCRIPTION:{description}
END:VEVENT
END:VCALENDAR";

    // --- PUT送信先(ユニークなICSファイル名を指定) ---
    string eventUri = $"{uri}{uid}.ics";

    using (var client = new HttpClient())
    {
        // Basic認証
        var authValue = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}"));
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authValue);

        // Content-Type: text/calendar
        var content = new StringContent(icsData, Encoding.UTF8, "text/calendar");

        // PUTリクエスト送信
        HttpResponseMessage response = await client.PutAsync(eventUri, content);

        if (response.IsSuccessStatusCode)
        {
            Console.WriteLine("予定を登録しました。");
        }
        else
        {
            Console.WriteLine($"エラー: {response.StatusCode}");
            string error = await response.Content.ReadAsStringAsync();
            Console.WriteLine(error);
        }
    }
}

4. 呼び出し例


await AddCalendarEventAsync(
    startDate: new DateTime(2025, 10, 25, 10, 0, 0),
    endDate:   new DateTime(2025, 10, 25, 11, 0, 0),
    subject: "営業会議",
    description: "来期製品ラインナップの確認",
    uri: "http://your-server-address/baikal/dav.php/calendars/your-user/your-calendar/",
    username: "your-user",
    password: "your-password"
);

5. ポイント

  • UID は各予定を一意に識別するため、Guid で自動生成しています。
  • ICSファイル名{uid}.ics として、CalDAV側でも識別可能にしています。
  • BaïkalはCalDAV準拠なので、PUT送信で即座にカレンダーへ反映されます。
  • 既存のUIDを同じURIにPUTすると、予定を上書きできます。

6. 応用:削除・更新

削除する場合は HttpClient.DeleteAsync(eventUri)、更新する場合は同じUIDで再度 PutAsync() を送信します。


// 削除例
await client.DeleteAsync(eventUri);

// 更新例(AddCalendarEventAsync 内で再PUT)
await client.PutAsync(eventUri, content);

7. まとめ

この関数をプロジェクトに組み込むことで、OutlookやInfCloudと同じCalDAVカレンダーに C#アプリケーションから直接予定を追加できます。
営業管理ツールや生産スケジュールの自動登録など、社内システムとの連携にも最適です。


8. WinForms具体例:ボタンから入力値を集めて登録する

Windowsフォーム(WinForms)の画面から、上記の方法を使ってボタンのクリックで入力値を集め、先ほどの AddCalendarEventAsync() を呼び出して予定を登録する例です。
以下のようなコントロールをフォームに配置してください(名前は例と同一にしてください):

  • DateTimePicker ×2:dtStart(開始)、dtEnd(終了)
  • TextBox ×5:txtSubjecttxtDescriptiontxtUritxtUsertxtPasswordtxtPassword は UseSystemPasswordChar = true 推奨
  • Button ×1:btnAdd(「予定を登録」)

フォームのコード(Form1.cs):


using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CalendarWinFormsSample
{
    public partial class Form1 : Form
    {
        // HttpClient は使い回す
        private static readonly HttpClient http = new HttpClient();

        public Form1()
        {
            InitializeComponent();

            // 例:24時間表示や初期値の調整
            dtStart.Format = DateTimePickerFormat.Custom;
            dtStart.CustomFormat = "yyyy/MM/dd HH:mm";
            dtEnd.Format = DateTimePickerFormat.Custom;
            dtEnd.CustomFormat = "yyyy/MM/dd HH:mm";

            // サンプル初期値(環境に合わせて書き換え)
            txtUri.Text = "http://your-server-address/baikal/dav.php/calendars/your-user/your-calendar/";
        }

        // 既出の登録関数(記事の「3. 登録関数の実装」をそのまま使用)
        public async Task AddCalendarEventAsync(
            DateTime startDate,
            DateTime endDate,
            string subject,
            string description,
            string uri,
            string username,
            string password)
        {
            // --- UID(予定を一意に識別) ---
            string uid = Guid.NewGuid().ToString() + "@example.com";

            // --- iCalendar データを生成 ---
            string icsData = $@"BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//YourCompany//CalDAV Client//EN
BEGIN:VEVENT
UID:{uid}
DTSTAMP:{DateTime.UtcNow:yyyyMMddTHHmmssZ}
DTSTART:{startDate:yyyyMMddTHHmmssZ}
DTEND:{endDate:yyyyMMddTHHmmssZ}
SUMMARY:{EscapeIcs(subject)}
DESCRIPTION:{EscapeIcs(description)}
END:VEVENT
END:VCALENDAR";

            // --- PUT送信先(ユニークなICSファイル名を指定) ---
            string eventUri = $"{uri}{uid}.ics";

            // Basic認証
            var authValue = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}"));
            http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authValue);

            // Content-Type: text/calendar
            var content = new StringContent(icsData, Encoding.UTF8, "text/calendar");

            // PUTリクエスト送信
            HttpResponseMessage response = await http.PutAsync(eventUri, content);

            if (!response.IsSuccessStatusCode)
            {
                string body = await response.Content.ReadAsStringAsync();
                throw new ApplicationException($"CalDAV登録エラー: {(int)response.StatusCode} {response.ReasonPhrase}\n{body}");
            }
        }

        // ICSの特殊文字を簡易エスケープ(カンマ・セミコロン・バックスラッシュ・改行)
        private static string EscapeIcs(string s)
        {
            if (string.IsNullOrEmpty(s)) return "";
            return s
                .Replace(@"\", @"\\")
                .Replace(";", @"\;")
                .Replace(",", @"\,")
                .Replace("\r\n", "\\n")
                .Replace("\n", "\\n");
        }

        // ボタンクリックで値を収集して登録
        private async void btnAdd_Click(object sender, EventArgs e)
        {
            btnAdd.Enabled = false;

            try
            {
                // 値の取得
                DateTime startDate = dtStart.Value;
                DateTime endDate   = dtEnd.Value;
                string subject     = txtSubject.Text?.Trim();
                string description = txtDescription.Text?.Trim();
                string uri         = txtUri.Text?.Trim();
                string username    = txtUser.Text?.Trim();
                string password    = txtPassword.Text; // パスワードはTrimしないほうが安全なことも

                // 入力チェック(必要に応じて強化)
                if (string.IsNullOrWhiteSpace(uri) || !uri.EndsWith("/"))
                {
                    MessageBox.Show("URI は末尾スラッシュ(/)で終わる CalDAV カレンダーURLを指定してください。", "入力エラー",
                        MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
                if (endDate <= startDate)
                {
                    MessageBox.Show("終了日時は開始日時より後にしてください。", "入力エラー",
                        MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
                if (string.IsNullOrWhiteSpace(subject))
                {
                    MessageBox.Show("件名(Subject)を入力してください。", "入力エラー",
                        MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }

                // 登録実行
                await AddCalendarEventAsync(
                    startDate: startDate,
                    endDate:   endDate,
                    subject:   subject,
                    description: description,
                    uri:         uri,
                    username:    username,
                    password:    password
                );

                MessageBox.Show("予定を登録しました。", "完了",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);

                // 必要に応じてフォームの入力をクリア
                // txtSubject.Clear(); txtDescription.Clear();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "エラー",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                btnAdd.Enabled = true;
            }
        }
    }
}

ポイント:

  • btnAdd_Clickasync void でOK(UIイベントハンドラの定石)。
  • CalDAVのURIは末尾スラッシュ必須(例:.../your-calendar/)。
  • HttpClient は毎回生成せず使い回すと安定&効率的。
  • ICSの特殊文字(カンマ/セミコロン/バックスラッシュ/改行)はエスケープしておくと安全。
  • サーバーがHTTPSの場合、自己署名証明書はWindowsの「信頼されたルート」に配布しておくと接続が安定。

このフォーム例をベースに、Excelや社内DBから予定行を取り込み、ループで複数件を登録することも可能です(行ごとに AddCalendarEventAsync() を実行)。

検索

年月ごとアーカイブ

フレンドブログ

Translate

自己紹介

自分の写真
映画が好き! 音楽好き! 演奏も好き! ミキシングが一番好き!

QooQ