| 112 | Lists of non-IConvertible types work the same: |
| 113 | {{{ |
| 114 | public class SomePage : System.Web.Page, IContinuation<IEnumerable<Project>, Customer> |
| 115 | { |
| 116 | IEnumerable<Project> arg0; |
| 117 | Customer arg1; |
| 118 | |
| 119 | override protected void OnInit(EventArgs e) |
| 120 | { |
| 121 | IEnumerable<Id<int, Project>> id0; |
| 122 | if (this.TryParse0(out id0)) |
| 123 | { |
| 124 | var projectIds = id0.Select(x => x.Key).ToList(); |
| 125 | arg0 = SomeDb.Projects.Where(x => projectIds.Contains(x.Id)); |
| 126 | } |
| 127 | |
| 128 | Id<int, Customer> id1; |
| 129 | if (this.TryParse1(out arg1)) |
| 130 | arg1 = SomeDb.Customers.Single(x => x.Id == id1.Key); |
| 131 | } |
| 132 | } |
| 133 | }}} |
| 134 | |
| 135 | = Clavis Setup = |
| 136 | |
| 137 | == Global.asax.cs == |
| 138 | |
| 139 | Clavis requires a very simple setup. In Global.asax.cs, you simply need to call {{{Continuation.Init}}} to initialize the Clavis library with a private 64-byte key: |
| 140 | {{{ |
| 141 | protected void Application_Start(object sender, EventArgs e) |
| 142 | { |
| 143 | var key = "ha6dMh+cymHn25ndckkQ9ajtzCu97frmpsmUzTLHEjwMp7nXMX/dqYfATANqNf5jy5Wvi1BFnz1293lc1D3KKw=="; |
| 144 | Continuation.Init(key); |
| 145 | } |
| 146 | }}} |
| 147 | This makes all URLs delegable, which is to say that no cookies or other type of user-specific context prevents a user from sharing this URL. His private URL carries his full credentials. |
| 148 | |
| 149 | If you wish to make URLs non-delegable, then use the other {{{Continuation.Init}}} overload where you can specify a custom context that is hashed with the default HMAC: |
| 150 | {{{ |
| 151 | protected void Application_Start(object sender, EventArgs e) |
| 152 | { |
| 153 | var key = "ha6dMh+cymHn25ndckkQ9ajtzCu97frmpsmUzTLHEjwMp7nXMX/dqYfATANqNf5jy5Wvi1BFnz1293lc1D3KKw=="; |
| 154 | Continuation.Init(key, () => |
| 155 | { |
| 156 | var x = HttpContext.Current.Session; |
| 157 | return x == null ? "" : x.SessionID; |
| 158 | }); |
| 159 | } |
| 160 | }}} |
| 161 | Here we use the default ASP.NET session id which is stored in cookies to ensure that users can't inadvertently leak their private URL. |
| 162 | |
| 163 | == Page.OnPreInit == |
| 164 | |
| 165 | The last step is to add continuation validation at some point in the page lifecycle. Clavis checks that all the protected parameters hash to the same HMAC value as specified in the URL. If they don't, an exception was thrown indicating that a protected parameter was incorrectly changed. I typically do this in Page.OnPreInit: |
| 166 | {{{ |
| 167 | protected override void OnPreInit(EventArgs e) |
| 168 | { |
| 169 | var k = this as IContinuationBase; |
| 170 | if (k != null) k.Validate(); |
| 171 | } |
| 172 | }}} |