からめもぶろぐ。

俺たちは雰囲気で OAuth をやっている

CSOM で通知を取得するときの仕様が鬼畜な件について

SharePoint にはリスト アイテムに変更があったときにメールで通知をしてくれる機能があります。上位互換の Power Automate を使うという方法もありますが、モダン UI にもちゃんとメニューがあって、組み込みのお手軽さもあるため、まだまだ使う機会は多いでしょう。

CSOM では Web.Alerts プロパティでサイトに設定されている通知の一覧を取得することができます。しかし思わぬところでうまくいかないことがありますのでご紹介しておきたいと思います。

ItemID プロパティを Load に含めるとエラーになる

通知にはリスト全体に設定するものと特定のリスト アイテムのみに設定するものがあります。それぞれは ListID プロパティと ItemID プロパティによって特定することができます。
試しに ListID プロパティと ItemID プロパティを取得してみたいと思います。それぞれは既定では読み込まれないので明示的に指定してあげる必要があります。

private static void Main(string[] args)
{
    var siteurl = "{{siteurl}}";
    var username = "{{username}}";
    var password = "{{password}}";
    var credential = new NetworkCredential(username, password);
    var context = new ClientContext(siteurl)
    {
        Credentials = new SharePointOnlineCredentials(credential.UserName, credential.SecurePassword)
    };
    context.Load(context.Web.Alerts, x => x.Include(y => y.ListID, y => y.ItemID));
    context.ExecuteQuery();
}

ところがこのコードを実行すると以下のエラーが発生することがあります。

Microsoft.SharePoint.Client.ServerException: 'ItemID is not available for this type of alert.'

リスト全体に設定する通知の場合、ItemID プロパティを参照しようとすると強制的にエラーになります。安全に読み込みたい場合は、それぞれの Alert について、AlertType プロパティを判断し、読み込むプロパティを変える必要があるということです。つまり、以下のようなコードになります。

private static void Main(string[] args)
{
    var siteurl = "{{siteurl}}";
    var username = "{{username}}";
    var password = "{{password}}";
    var credential = new NetworkCredential(username, password);
    var context = new ClientContext(siteurl)
    {
        Credentials = new SharePointOnlineCredentials(credential.UserName, credential.SecurePassword)
    };
    context.Load(context.Web.Alerts);
    context.ExecuteQuery();
    foreach (var alert in context.Web.Alerts)
    {
        switch (alert.AlertType) {
            case AlertType.List:
                context.Load(alert, x => x.ListID);
                break;
            case AlertType.Item:
                context.Load(alert, x => x.ListID, x => x.ItemID);
                break;
            default:
                context.Load(alert);
                break;
        }
        context.ExecuteQuery();
    }
}

AlertTime プロパティを Load に含めるとエラーになる

同様に、AlertTime プロパティも読み込むとエラーが発生することがあります。

private static void Main(string[] args)
{
    var siteurl = "{{siteurl}}";
    var username = "{{username}}";
    var password = "{{password}}";
    var credential = new NetworkCredential(username, password);
    var context = new ClientContext(siteurl)
    {
        Credentials = new SharePointOnlineCredentials(credential.UserName, credential.SecurePassword)
    };
    context.Load(context.Web.Alerts, x => x.Include(y => y.AlertTime));
    context.ExecuteQuery();
}

このコードは以下のエラーを発生させることがあります。

Microsoft.SharePoint.Client.ServerException: 'AlertTime property cannot be used on immediate alerts.'

コードは省略しますが、こちらの場合も AlertFrequency プロパティをみて Immediate かそうでないかで読み込みを変える必要があります。

まとめ

完全に使う側のこと考えないで設計しているよなとしか思えないです。もし使われる場合は十分注意してください。