Somehow, I've made it through over five years of SharePoint development without ever having to play with alerts. (I love whenever my posts start out that way! It's like if I haven't had to deal with it, then it must be easy, right?)
Anyway, my first time came first thing today. All I had to do was write a service that, when passed a URL, pareses it, opens the appropriate SPWeb and SPList objects, and wires up an SPAlert for the current user. Cake...seemingly. Well, I ran into one little issue that, as it turned out, made me deserve to have to work through lunch to finish this code on time.
Every blog that outlines how to programmatically create an alert all go through almost exactly the same procedure, so I'll leave you to visit here for the actual code. This dude does a good job of pointing out some of the nuances of working with alerts in your code.
My problem, however, was a bit deeper than having to worry about setting one property of an object before another (read the link above). My problem was the following love note from SharePoint:
Isn't it adorable when Exceptions try to give you a little hint? It's like asking someone if their broken iPod has the volume at zero. Ugh.
This was especially vexing, because the List property of the SPAlert object accepts an instance of a list; the fact that I was able to instantiate an SPList object leaves me to believe that it does indeed exist. So why is my list suffering from existential problems?
Because it does indeed NOT exist - at least not where I told the alert that it existed. The problem is actually simple. When you get an SPUser from the CurrentUser property of an SPWeb, that user's alerts collection only contains the alerts from the particular sub site represented by that web! So guess what happens if you feed it a list that was, let's say, instantiated from a different web?
You guessed it: the error above.
So, yeah, don't do that.