C#からBaïkal(CalDAV)へ予定を登録する
ここでは、C#からCalDAV(Baïkal)サーバーに予定を登録する処理を関数化します。
引数として startDate・endDate・subject・description・uri を受け取り、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:txtSubject、txtDescription、txtUri、txtUser、txtPassword(txtPassword は 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_Clickはasync voidでOK(UIイベントハンドラの定石)。- CalDAVのURIは末尾スラッシュ必須(例:
.../your-calendar/)。 HttpClientは毎回生成せず使い回すと安定&効率的。- ICSの特殊文字(カンマ/セミコロン/バックスラッシュ/改行)はエスケープしておくと安全。
- サーバーがHTTPSの場合、自己署名証明書はWindowsの「信頼されたルート」に配布しておくと接続が安定。
このフォーム例をベースに、Excelや社内DBから予定行を取り込み、ループで複数件を登録することも可能です(行ごとに AddCalendarEventAsync() を実行)。

0 件のコメント:
コメントを投稿