Namespace: ITHit.Server.Extensibility
public interface IMethodHandlerAsync<THierarchyItemAsync> where THierarchyItemAsync : IHierarchyItemBaseAsync public interface IMethodHandlerAsync<THierarchyItemAsync> where THierarchyItemAsync : IHierarchyItemBaseAsync
The IMethodHandlerAsyncTHierarchyItemAsync type exposes the following members.
Name | Description | |
---|---|---|
EnableInputDebugLogging |
Determines whether input read by this handler shall be logged if debug logging is enabled.
| |
EnableOutputBuffering |
Determines whether engine can buffer content to calculate content length.
| |
EnableOutputDebugLogging |
Determines whether output produces by this handler shall be logged if debug logging
is enabled.
|
Name | Description | |
---|---|---|
AppliesTo |
Determines whether this method shall be enlisted in 'supported-method-set' for
item.
| |
ProcessRequestAsync |
Enables processing of HTTP Web requests by a custom handler.
|
The IT Hit Server Engine allows creating custom HTTP handlers and replacing original engine handlers. To add or replace handler call RegisterMethodHandler(String, IMethodHandlerAsyncTHierarchyItemAsync) method passing HTTP method name and object instance implementing IMethodHandlerAsyncTHierarchyItemAsync. The original handler, if any, is returned from RegisterMethodHandler(String, IMethodHandlerAsyncTHierarchyItemAsync) method.
The ProcessRequestAsync(ContextAsyncTHierarchyItemAsync, THierarchyItemAsync) method of this interface is called by the engine during RunAsync(ContextAsyncTHierarchyItemAsync) call. The hierarchy item returned from GetHierarchyItemAsync(String) is passed to ProcessRequest method as a parameter.
The handler must call BeforeResponseAsync when all update methods have been called and the handler is about to start writing response.
The code below is part of 'WebDAVServer.FileSystemStorage.AspNet' C# & VB samples provided with the SDK.
internal class MyCustomGetHandler : IMethodHandlerAsync<IHierarchyItemAsync> { public IMethodHandlerAsync<IHierarchyItemAsync> OriginalHandler { get; set; } public bool EnableOutputBuffering { get { return false; } } public bool EnableOutputDebugLogging { get { return false; } } public bool EnableInputDebugLogging { get { return false; } } private readonly string htmlPath; public MyCustomGetHandler(string contentRootPathFolder) { this.htmlPath = contentRootPathFolder; } public async Task ProcessRequestAsync(ContextAsync<IHierarchyItemAsync> context, IHierarchyItemAsync item) { string urlPath = context.Request.RawUrl.Substring(context.Request.ApplicationPath.TrimEnd('/').Length); if (item is IItemCollectionAsync) { // In case of GET requests to WebDAV folders we serve a web page to display // any information about this server and how to use it. // Remember to call EnsureBeforeResponseWasCalledAsync here if your context implementation // makes some useful things in BeforeResponseAsync. await context.EnsureBeforeResponseWasCalledAsync(); IHttpAsyncHandler page = (IHttpAsyncHandler)System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath( "~/MyCustomHandlerPage.aspx", typeof(MyCustomHandlerPage)); if(Type.GetType("Mono.Runtime") != null) { page.ProcessRequest(HttpContext.Current); } else { // Here we call BeginProcessRequest instead of ProcessRequest to start an async page execution and be able to call RegisterAsyncTask if required. // To call APM method (Begin/End) from TAP method (Task/async/await) the Task.FromAsync must be used. await Task.Factory.FromAsync(page.BeginProcessRequest, page.EndProcessRequest, HttpContext.Current, null); } } else { await OriginalHandler.ProcessRequestAsync(context, item); } } public bool AppliesTo(IHierarchyItemAsync item) { return item is IFolderAsync || OriginalHandler.AppliesTo(item); } }
The code below is part of 'CalDAVServer.SqlStorage.AspNet' C# & VB samples provided with the SDK.
internal class MyCustomGetHandler : IMethodHandlerAsync<IHierarchyItemAsync> { public IMethodHandlerAsync<IHierarchyItemAsync> OriginalHandler { get; set; } public bool EnableOutputBuffering { get { return false; } } public bool EnableOutputDebugLogging { get { return false; } } public bool EnableInputDebugLogging { get { return false; } } private readonly string htmlPath; public MyCustomGetHandler(string contentRootPathFolder) { this.htmlPath = contentRootPathFolder; } public async Task ProcessRequestAsync(ContextAsync<IHierarchyItemAsync> context, IHierarchyItemAsync item) { string urlPath = context.Request.RawUrl.Substring(context.Request.ApplicationPath.TrimEnd('/').Length); if (item is IItemCollectionAsync) { // In case of GET requests to WebDAV folders we serve a web page to display // any information about this server and how to use it. // Remember to call EnsureBeforeResponseWasCalledAsync here if your context implementation // makes some useful things in BeforeResponseAsync. await context.EnsureBeforeResponseWasCalledAsync(); // Request to iOS/OS X CalDAV/CardDAV profile. if (context.Request.RawUrl.EndsWith("?connect")) { await WriteProfileAsync(context, item, htmlPath); return; } IHttpAsyncHandler page = (IHttpAsyncHandler)System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath( "~/MyCustomHandlerPage.aspx", typeof(MyCustomHandlerPage)); if(Type.GetType("Mono.Runtime") != null) { page.ProcessRequest(HttpContext.Current); } else { // Here we call BeginProcessRequest instead of ProcessRequest to start an async page execution and be able to call RegisterAsyncTask if required. // To call APM method (Begin/End) from TAP method (Task/async/await) the Task.FromAsync must be used. await Task.Factory.FromAsync(page.BeginProcessRequest, page.EndProcessRequest, HttpContext.Current, null); } } else { await OriginalHandler.ProcessRequestAsync(context, item); } } public bool AppliesTo(IHierarchyItemAsync item) { return item is IFolderAsync || OriginalHandler.AppliesTo(item); } private async Task WriteProfileAsync(ContextAsync<IHierarchyItemAsync> context, IHierarchyItemBaseAsync item, string htmlPath) { string mobileconfigFileName = null; string decription = null; if (item is ICalendarFolderAsync) { mobileconfigFileName = "CalDAV.AppleProfileTemplete.mobileconfig"; decription = (item as ICalendarFolderAsync).CalendarDescription; } decription = !string.IsNullOrEmpty(decription) ? decription : item.Name; string templateContent = null; using (TextReader reader = new StreamReader(Path.Combine(htmlPath, mobileconfigFileName))) { templateContent = await reader.ReadToEndAsync(); } Uri url = new Uri(context.Request.UrlPrefix); string payloadUUID = item.Path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Last(); // PayloadUUID string profile = string.Format(templateContent , url.Host // host name , item.Path // CalDAV / CardDAV Principal URL. Here we can return (await (item as ICurrentUserPrincipalAsync).GetCurrentUserPrincipalAsync()).Path if needed. , (context as DavContext).Identity.Name // user name , url.Port // port , (url.Scheme == "https").ToString().ToLower() // SSL , decription // CardDAV / CardDAV Account Description , Assembly.GetAssembly(this.GetType()).GetName().Version.ToString() , Assembly.GetAssembly(typeof(DavEngineAsync)).GetName().Version.ToString() , payloadUUID ); byte[] profileBytes = SignProfile(context, profile); context.Response.ContentType = "application/x-apple-aspen-config"; context.Response.AddHeader("Content-Disposition", "attachment; filename=profile.mobileconfig"); context.Response.ContentLength = profileBytes.Length; await context.Response.OutputStream.WriteAsync(profileBytes, 0, profileBytes.Length); } private byte[] SignProfile(ContextAsync<IHierarchyItemAsync> context, string profile) { // Here you will sign your profile with SSL certificate to avoid "Unsigned" warning on iOS and OS X. // For demo purposes we just return the profile content unmodified. return context.Engine.ContentEncoding.GetBytes(profile); } }
The code below is part of 'CardDAVServer.SqlStorage.AspNet' C# & VB samples provided with the SDK.
internal class MyCustomGetHandler : IMethodHandlerAsync<IHierarchyItemAsync> { public IMethodHandlerAsync<IHierarchyItemAsync> OriginalHandler { get; set; } public bool EnableOutputBuffering { get { return false; } } public bool EnableOutputDebugLogging { get { return false; } } public bool EnableInputDebugLogging { get { return false; } } private readonly string htmlPath; public MyCustomGetHandler(string contentRootPathFolder) { this.htmlPath = contentRootPathFolder; } public async Task ProcessRequestAsync(ContextAsync<IHierarchyItemAsync> context, IHierarchyItemAsync item) { string urlPath = context.Request.RawUrl.Substring(context.Request.ApplicationPath.TrimEnd('/').Length); if (item is IItemCollectionAsync) { // In case of GET requests to WebDAV folders we serve a web page to display // any information about this server and how to use it. // Remember to call EnsureBeforeResponseWasCalledAsync here if your context implementation // makes some useful things in BeforeResponseAsync. await context.EnsureBeforeResponseWasCalledAsync(); // Request to iOS/OS X CalDAV/CardDAV profile. if (context.Request.RawUrl.EndsWith("?connect")) { await WriteProfileAsync(context, item, htmlPath); return; } IHttpAsyncHandler page = (IHttpAsyncHandler)System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath( "~/MyCustomHandlerPage.aspx", typeof(MyCustomHandlerPage)); if(Type.GetType("Mono.Runtime") != null) { page.ProcessRequest(HttpContext.Current); } else { // Here we call BeginProcessRequest instead of ProcessRequest to start an async page execution and be able to call RegisterAsyncTask if required. // To call APM method (Begin/End) from TAP method (Task/async/await) the Task.FromAsync must be used. await Task.Factory.FromAsync(page.BeginProcessRequest, page.EndProcessRequest, HttpContext.Current, null); } } else { await OriginalHandler.ProcessRequestAsync(context, item); } } public bool AppliesTo(IHierarchyItemAsync item) { return item is IFolderAsync || OriginalHandler.AppliesTo(item); } private async Task WriteProfileAsync(ContextAsync<IHierarchyItemAsync> context, IHierarchyItemBaseAsync item, string htmlPath) { string mobileconfigFileName = null; string decription = null; if (item is IAddressbookFolderAsync) { mobileconfigFileName = "CardDAV.AppleProfileTemplete.mobileconfig"; decription = (item as IAddressbookFolderAsync).AddressbookDescription; } decription = !string.IsNullOrEmpty(decription) ? decription : item.Name; string templateContent = null; using (TextReader reader = new StreamReader(Path.Combine(htmlPath, mobileconfigFileName))) { templateContent = await reader.ReadToEndAsync(); } Uri url = new Uri(context.Request.UrlPrefix); string payloadUUID = item.Path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Last(); // PayloadUUID string profile = string.Format(templateContent , url.Host // host name , item.Path // CalDAV / CardDAV Principal URL. Here we can return (await (item as ICurrentUserPrincipalAsync).GetCurrentUserPrincipalAsync()).Path if needed. , (context as DavContext).Identity.Name // user name , url.Port // port , (url.Scheme == "https").ToString().ToLower() // SSL , decription // CardDAV / CardDAV Account Description , Assembly.GetAssembly(this.GetType()).GetName().Version.ToString() , Assembly.GetAssembly(typeof(DavEngineAsync)).GetName().Version.ToString() , payloadUUID ); byte[] profileBytes = SignProfile(context, profile); context.Response.ContentType = "application/x-apple-aspen-config"; context.Response.AddHeader("Content-Disposition", "attachment; filename=profile.mobileconfig"); context.Response.ContentLength = profileBytes.Length; await context.Response.OutputStream.WriteAsync(profileBytes, 0, profileBytes.Length); } private byte[] SignProfile(ContextAsync<IHierarchyItemAsync> context, string profile) { // Here you will sign your profile with SSL certificate to avoid "Unsigned" warning on iOS and OS X. // For demo purposes we just return the profile content unmodified. return context.Engine.ContentEncoding.GetBytes(profile); } }