@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApplication1.models
{
public class GetSubscribersForList
{
public string email { get; set; },

public int id { get; set; },
public string name { get; set; },
// "tags": [],
}
}
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApplication1.models
{
public class GetTag
{
public string tag { get; set; }


} //end public class
}
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApplication1.models
{
public class UpdateSubscriber
{
public string email { get; set; },
public string tag { get; set; }
}
}
@@ -1,7 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AjaxControlToolkit" version="18.1.0" targetFramework="net461" />
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net461" />
<package id="Microsoft.AspNet.Identity.Owin" version="2.2.1" targetFramework="net461" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.4" targetFramework="net461" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.4" targetFramework="net461" />
<package id="Microsoft.AspNet.WebApi.Owin" version="5.2.4" targetFramework="net461" />
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.8" targetFramework="net461" />
<package id="Microsoft.Net.Compilers" version="2.4.0" targetFramework="net461" developmentDependency="true" />
<package id="Microsoft.Owin" version="4.0.0" targetFramework="net461" />
<package id="Microsoft.Owin.Host.SystemWeb" version="4.0.0" targetFramework="net461" />
<package id="Microsoft.Owin.Security" version="4.0.0" targetFramework="net461" />
<package id="Microsoft.Owin.Security.Cookies" version="2.1.0" targetFramework="net461" />
<package id="Microsoft.Owin.Security.OAuth" version="4.0.0" targetFramework="net461" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" />
<package id="Owin" version="1.0" targetFramework="net461" />
<package id="S22.Imap.PullReq-96" version="3.6.0.50130" targetFramework="net461" />
</packages>
@@ -5,8 +5,6 @@ VisualStudioVersion = 15.0.27428.2015
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApplication1", "WebApplication1\WebApplication1.csproj", "{C3BB0DFD-18A8-40E1-9770-B04F0BCBC81A}"
EndProject
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "PythonApplication1", "PythonApplication1\PythonApplication1.pyproj", "{CD9FEAA0-14FA-4A5B-8D20-5562A57F8733}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -17,8 +15,6 @@ Global
{C3BB0DFD-18A8-40E1-9770-B04F0BCBC81A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3BB0DFD-18A8-40E1-9770-B04F0BCBC81A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3BB0DFD-18A8-40E1-9770-B04F0BCBC81A}.Release|Any CPU.Build.0 = Release|Any CPU
{CD9FEAA0-14FA-4A5B-8D20-5562A57F8733}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CD9FEAA0-14FA-4A5B-8D20-5562A57F8733}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -0,0 +1,23 @@
Imports System.Web
Imports System.Web.Optimization

Public Module BundleConfig
' For more information on bundling, visit https://go.microsoft.com/fwlink/?LinkId=301862
Public Sub RegisterBundles(ByVal bundles As BundleCollection)
bundles.Add(New ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"))

' Use the development version of Modernizr to develop with and learn from. Then, when you're
' ready for production, use the build tool at https://modernizr.com to pick only the tests you need.
bundles.Add(New ScriptBundle("~/bundles/modernizr").Include(
"~/Scripts/modernizr-*"))

bundles.Add(New ScriptBundle("~/bundles/bootstrap").Include(
"~/Scripts/bootstrap.js",
"~/Scripts/respond.js"))

bundles.Add(New StyleBundle("~/Content/css").Include(
"~/Content/bootstrap.css",
"~/Content/site.css"))
End Sub
End Module
@@ -0,0 +1,8 @@
Imports System.Web
Imports System.Web.Mvc

Public Module FilterConfig
Public Sub RegisterGlobalFilters(ByVal filters As GlobalFilterCollection)
filters.Add(New HandleErrorAttribute())
End Sub
End Module
@@ -0,0 +1,18 @@
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Web
Imports System.Web.Mvc
Imports System.Web.Routing

Public Module RouteConfig
Public Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")

routes.MapRoute(
name:="Default",
url:="{controller}/{action}/{id}",
defaults:=New With {.controller = "Home", .action = "Index", .id = UrlParameter.Optional}
)
End Sub
End Module
@@ -0,0 +1,75 @@
Imports System.Collections.Generic
Imports System.Linq
Imports Microsoft.AspNet.Identity
Imports Microsoft.AspNet.Identity.EntityFramework
Imports Microsoft.Owin
Imports Microsoft.Owin.Security.Cookies
Imports Microsoft.Owin.Security.Google
Imports Microsoft.Owin.Security.OAuth
Imports Owin

Public Partial Class Startup
Private Shared _OAuthOptions As OAuthAuthorizationServerOptions
Private Shared _PublicClientId As String

Public Shared Property OAuthOptions() As OAuthAuthorizationServerOptions
Get
Return _OAuthOptions
End Get
Private Set
_OAuthOptions = Value
End Set
End Property

Public Shared Property PublicClientId() As String
Get
Return _PublicClientId
End Get
Private Set
_PublicClientId = Value
End Set
End Property

' For more information on configuring authentication, please visit https://go.microsoft.com/fwlink/?LinkId=301864
Public Sub ConfigureAuth(app As IAppBuilder)
' Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(AddressOf ApplicationDbContext.Create)
app.CreatePerOwinContext(Of ApplicationUserManager)(AddressOf ApplicationUserManager.Create)

' Enable the application to use a cookie to store information for the signed in user
' and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(New CookieAuthenticationOptions())
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie)

' Configure the application for OAuth based flow
' In production mode set AllowInsecureHttp = False
PublicClientId = "self"
OAuthOptions = New OAuthAuthorizationServerOptions() With {
.TokenEndpointPath = New PathString("/Token"),
.Provider = New ApplicationOAuthProvider(PublicClientId),
.AuthorizeEndpointPath = New PathString("/api/Account/ExternalLogin"),
.AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
.AllowInsecureHttp = True
}

' Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions)

' Uncomment the following lines to enable logging in with third party login providers
'app.UseMicrosoftAccountAuthentication(
' clientId:="",
' clientSecret:="")

'app.UseTwitterAuthentication(
' consumerKey:="",
' consumerSecret:="")

'app.UseFacebookAuthentication(
' appId:="",
' appSecret:="")

'app.UseGoogleAuthentication(New GoogleOAuth2AuthenticationOptions() With {
' .ClientId = "",
' .ClientSecret = ""})
End Sub
End Class
@@ -0,0 +1,22 @@
Imports System.Net.Http
Imports System.Web.Http
Imports Microsoft.Owin.Security.OAuth
Imports Newtonsoft.Json.Serialization

Public Module WebApiConfig
Public Sub Register(config As HttpConfiguration)
' Web API configuration and services
' Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication()
config.Filters.Add(New HostAuthenticationFilter(OAuthDefaults.AuthenticationType))

' Web API routes
config.MapHttpAttributeRoutes()

config.Routes.MapHttpRoute(
name:="DefaultApi",
routeTemplate:="api/{controller}/{id}",
defaults:=New With { .id = RouteParameter.Optional }
)
End Sub
End Module
@@ -0,0 +1,40 @@
Imports System.Threading.Tasks
Imports Microsoft.AspNet.Identity
Imports Microsoft.AspNet.Identity.EntityFramework
Imports Microsoft.AspNet.Identity.Owin
Imports Microsoft.Owin

' Configure the application user manager used in this application. UserManager is defined in ASP.NET Identity and is used by the application.
Public Class ApplicationUserManager
Inherits UserManager(Of ApplicationUser)

Public Sub New(store As IUserStore(Of ApplicationUser))
MyBase.New(store)
End Sub

Public Shared Function Create(options As IdentityFactoryOptions(Of ApplicationUserManager), context As IOwinContext) As ApplicationUserManager
Dim manager = New ApplicationUserManager(New UserStore(Of ApplicationUser)(context.Get(Of ApplicationDbContext)()))

' Configure validation logic for usernames
manager.UserValidator = New UserValidator(Of ApplicationUser)(manager) With {
.AllowOnlyAlphanumericUserNames = False,
.RequireUniqueEmail = True
}

' Configure validation logic for passwords
manager.PasswordValidator = New PasswordValidator With {
.RequiredLength = 6,
.RequireNonLetterOrDigit = True,
.RequireDigit = True,
.RequireLowercase = True,
.RequireUppercase = True
}

Dim dataProtectionProvider = options.DataProtectionProvider
If (dataProtectionProvider IsNot Nothing) Then
manager.UserTokenProvider = New DataProtectorTokenProvider(Of ApplicationUser)(dataProtectionProvider.Create("ASP.NET Identity"))
End If

Return manager
End Function
End Class
@@ -0,0 +1,3 @@
Public Class startup

End Class
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<ApplicationInsights xmlns="http://schemas.microsoft.com/ApplicationInsights/2013/Settings">
<TelemetryInitializers>
<Add Type="Microsoft.ApplicationInsights.DependencyCollector.HttpDependenciesParsingTelemetryInitializer, Microsoft.AI.DependencyCollector"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.AzureRoleEnvironmentTelemetryInitializer, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.AzureWebAppRoleEnvironmentTelemetryInitializer, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.BuildInfoConfigComponentVersionTelemetryInitializer, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.Web.WebTestTelemetryInitializer, Microsoft.AI.Web"/>
<Add Type="Microsoft.ApplicationInsights.Web.SyntheticUserAgentTelemetryInitializer, Microsoft.AI.Web">
<!-- Extended list of bots:
search|spider|crawl|Bot|Monitor|BrowserMob|BingPreview|PagePeeker|WebThumb|URL2PNG|ZooShot|GomezA|Google SketchUp|Read Later|KTXN|KHTE|Keynote|Pingdom|AlwaysOn|zao|borg|oegp|silk|Xenu|zeal|NING|htdig|lycos|slurp|teoma|voila|yahoo|Sogou|CiBra|Nutch|Java|JNLP|Daumoa|Genieo|ichiro|larbin|pompos|Scrapy|snappy|speedy|vortex|favicon|indexer|Riddler|scooter|scraper|scrubby|WhatWeb|WinHTTP|voyager|archiver|Icarus6j|mogimogi|Netvibes|altavista|charlotte|findlinks|Retreiver|TLSProber|WordPress|wsr-agent|http client|Python-urllib|AppEngine-Google|semanticdiscovery|facebookexternalhit|web/snippet|Google-HTTP-Java-Client-->
<Filters>search|spider|crawl|Bot|Monitor|AlwaysOn</Filters>
</Add>
<Add Type="Microsoft.ApplicationInsights.Web.ClientIpHeaderTelemetryInitializer, Microsoft.AI.Web"/>
<Add Type="Microsoft.ApplicationInsights.Web.OperationNameTelemetryInitializer, Microsoft.AI.Web"/>
<Add Type="Microsoft.ApplicationInsights.Web.OperationCorrelationTelemetryInitializer, Microsoft.AI.Web"/>
<Add Type="Microsoft.ApplicationInsights.Web.UserTelemetryInitializer, Microsoft.AI.Web"/>
<Add Type="Microsoft.ApplicationInsights.Web.AuthenticatedUserIdTelemetryInitializer, Microsoft.AI.Web"/>
<Add Type="Microsoft.ApplicationInsights.Web.AccountIdTelemetryInitializer, Microsoft.AI.Web"/>
<Add Type="Microsoft.ApplicationInsights.Web.SessionTelemetryInitializer, Microsoft.AI.Web"/>
</TelemetryInitializers>
<TelemetryModules>
<Add Type="Microsoft.ApplicationInsights.DependencyCollector.DependencyTrackingTelemetryModule, Microsoft.AI.DependencyCollector"/>
<Add Type="Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.PerformanceCollectorModule, Microsoft.AI.PerfCounterCollector">
<!--
Use the following syntax here to collect additional performance counters:
<Counters>
<Add PerformanceCounter="\Process(??APP_WIN32_PROC??)\Handle Count" ReportAs="Process handle count" />
...
</Counters>
PerformanceCounter must be either \CategoryName(InstanceName)\CounterName or \CategoryName\CounterName
NOTE: performance counters configuration will be lost upon NuGet upgrade.
The following placeholders are supported as InstanceName:
??APP_WIN32_PROC?? - instance name of the application process for Win32 counters.
??APP_W3SVC_PROC?? - instance name of the application IIS worker process for IIS/ASP.NET counters.
??APP_CLR_PROC?? - instance name of the application CLR process for .NET counters.
-->
</Add>
<Add Type="Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse.QuickPulseTelemetryModule, Microsoft.AI.PerfCounterCollector"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.DeveloperModeWithDebuggerAttachedTelemetryModule, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.UnhandledExceptionTelemetryModule, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.UnobservedExceptionTelemetryModule, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.Web.RequestTrackingTelemetryModule, Microsoft.AI.Web">
<Handlers>
<!--
Add entries here to filter out additional handlers:
NOTE: handler configuration will be lost upon NuGet upgrade.
-->
<Add>System.Web.Handlers.TransferRequestHandler</Add>
<Add>Microsoft.VisualStudio.Web.PageInspector.Runtime.Tracing.RequestDataHttpHandler</Add>
<Add>System.Web.StaticFileHandler</Add>
<Add>System.Web.Handlers.AssemblyResourceLoader</Add>
<Add>System.Web.Optimization.BundleHandler</Add>
<Add>System.Web.Script.Services.ScriptHandlerFactory</Add>
<Add>System.Web.Handlers.TraceHandler</Add>
<Add>System.Web.Services.Discovery.DiscoveryRequestHandler</Add>
<Add>System.Web.HttpDebugHandler</Add>
</Handlers>
</Add>
<Add Type="Microsoft.ApplicationInsights.Web.ExceptionTrackingTelemetryModule, Microsoft.AI.Web"/>
</TelemetryModules>
<TelemetryProcessors>
<Add Type="Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse.QuickPulseTelemetryProcessor, Microsoft.AI.PerfCounterCollector"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.AdaptiveSamplingTelemetryProcessor, Microsoft.AI.ServerTelemetryChannel">
<MaxTelemetryItemsPerSecond>5</MaxTelemetryItemsPerSecond>
</Add>
</TelemetryProcessors>
<TelemetryChannel Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.ServerTelemetryChannel, Microsoft.AI.ServerTelemetryChannel"/>
<!--
Learn more about Application Insights configuration with ApplicationInsights.config here:
http://go.microsoft.com/fwlink/?LinkID=513840
Note: If not present, please add <InstrumentationKey>Your Key</InstrumentationKey> to the top of this file.
--></ApplicationInsights>
@@ -0,0 +1,41 @@
Imports System
Imports System.Runtime.CompilerServices
Imports System.Text
Imports System.Web
Imports System.Web.Http.Description

Namespace Areas.HelpPage
Public Module ApiDescriptionExtensions
'''<summary>
'''Generates an URI-friendly ID for the <see cref="ApiDescription"/>. E.g. "Get-Values-id_name" instead of "GetValues/{id}?name={name}"
'''</summary>
'''<param name="description">The <see cref="ApiDescription"/>.</param>
'''<returns>The ID as a string.</returns>
<Extension()>
Public Function GetFriendlyId(ByVal description As ApiDescription) As String
Dim path As String = description.RelativePath
Dim urlParts() As String = path.Split("?"c)
Dim localPath As String = urlParts(0)

Dim queryKeyString As String = Nothing

If (urlParts.Length > 1) Then
Dim query As String = urlParts(1)
Dim queryKeys() As String = HttpUtility.ParseQueryString(query).AllKeys
queryKeyString = String.Join("_", queryKeys)
End If

Dim friendlyPath As New StringBuilder

friendlyPath.AppendFormat("{0}-{1}",
description.HttpMethod.Method,
localPath.Replace("/", "-").Replace("{", String.Empty).Replace("}", String.Empty))

If (Not queryKeyString Is Nothing) Then
friendlyPath.AppendFormat("_{0}", queryKeyString.Replace(".", "-"))
End If

GetFriendlyId = friendlyPath.ToString()
End Function
End Module
End Namespace
@@ -0,0 +1,107 @@
' Uncomment the following to provide samples for PageResult(Of T). Must also add the Microsoft.AspNet.WebApi.OData
' package to your project.
''#Const Handle_PageResultOfT = 1

Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.Diagnostics.CodeAnalysis
Imports System.Linq
Imports System.Net.Http.Headers
Imports System.Reflection
Imports System.Web
Imports System.Web.Http
#If Handle_PageResultOfT Then
Imports System.Web.Http.OData
#End If

Namespace Areas.HelpPage
''' <summary>
''' Use this class to customize the Help Page.
''' For example you can set a custom <see cref="System.Web.Http.Description.IDocumentationProvider"/> to supply the documentation
''' or you can provide the samples for the requests/responses.
''' </summary>
Public Module HelpPageConfig
<SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters",
MessageId:="accessAPI.Areas.HelpPage.TextSample.#ctor(System.String)",
Justification:="End users may choose to merge this string with existing localized resources.")>
<SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly",
MessageId:="bsonspec",
Justification:="Part of a URI.")>
Public Sub Register(config As HttpConfiguration)
'' Uncomment the following to use the documentation from XML documentation file.
'config.SetDocumentationProvider(New XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml")))

'' Uncomment the following to use "sample string" as the sample for all actions that have string as the body parameter or return type.
'' Also, the string arrays will be used for IEnumerable(Of String). The sample objects will be serialized into different media type
'' formats by the available formatters.
'config.SetSampleObjects(New Dictionary(Of Type, Object) From
'{
' {GetType(String), "sample string"},
' {GetType(IEnumerable(Of String)), New String() {"sample 1", "sample 2"}}
'})

' Extend the following to provide factories for types not handled automatically (those lacking parameterless
' constructors) or for which you prefer to use non-default property values. Line below provides a fallback
' since automatic handling will fail and GeneratePageResult handles only a single type.
#If Handle_PageResultOfT Then
config.GetHelpPageSampleGenerator().SampleObjectFactories.Add(AddressOf GeneratePageResult)
#End If

' Extend the following to use a preset object directly as the sample for all actions that support a media
' type, regardless of the body parameter or return type. The lines below avoid display of binary content.
' The BsonMediaTypeFormatter (if available) is not used to serialize the TextSample object.
config.SetSampleForMediaType(
New TextSample("Binary JSON content. See http://bsonspec.org for details."),
New MediaTypeHeaderValue("application/bson"))

'' Uncomment the following to use "[0]=foo&[1]=bar" directly as the sample for all actions that support form URL encoded format
'' and have IEnumerable(Of String) as the body parameter or return type.
'config.SetSampleForType("[0]=foo&[1]=bar", New MediaTypeHeaderValue("application/x-www-form-urlencoded"), GetType(IEnumerable(Of String)))

'' Uncomment the following to use "1234" directly as the request sample for media type "text/plain" on the controller named "Values"
'' and action named "Put".
'config.SetSampleRequest("1234", New MediaTypeHeaderValue("text/plain"), "Values", "Put")

'' Uncomment the following to use the image on "../images/aspNetHome.png" directly as the response sample for media type "image/png"
'' on the controller named "Values" and action named "Get" with parameter "id".
'config.SetSampleResponse(New ImageSample("../images/aspNetHome.png"), New MediaTypeHeaderValue("image/png"), "Values", "Get", "id")

'' Uncomment the following to correct the sample request when the action expects an HttpRequestMessage with ObjectContent(Of string).
'' The sample will be generated as if the controller named "Values" and action named "Get" were having String as the body parameter.
'config.SetActualRequestType(GetType(String), "Values", "Get")

'' Uncomment the following to correct the sample response when the action returns an HttpResponseMessage with ObjectContent(Of String).
'' The sample will be generated as if the controller named "Values" and action named "Post" were returning a String.
'config.SetActualResponseType(GetType(String), "Values", "Post")
End Sub

#If Handle_PageResultOfT Then
Private Function GeneratePageResult(sampleGenerator As HelpPageSampleGenerator, type As Type) As Object
If type.IsGenericType Then
Dim openGenericType As Type = type.GetGenericTypeDefinition()
If openGenericType = GetType(PageResult(Of )) Then
' Get the T in PageResult(Of T)
Dim typeParameters() As Type = type.GetGenericArguments()
Debug.Assert(typeParameters.Length = 1)

' Create an enumeration to pass as the first parameter to the PageResult(Of T) constuctor
Dim itemsType As Type = GetType(List(Of )).MakeGenericType(typeParameters)
Dim items As Object = sampleGenerator.GetSampleObject(itemsType)

' Fill in the other information needed to invoke the PageResult(Of T) constuctor
Dim parameterTypes() As Type = New Type() {itemsType, GetType(Uri), GetType(Long?)}
Dim parameters() As Object = New Object() {items, Nothing, CLng(ObjectGenerator.DefaultCollectionSize)}

' Call PageResult(items As IEnumerable(Of T), nextPageLink As Uri, count As Long?) constructor
Dim constructor As ConstructorInfo = type.GetConstructor(parameterTypes)
Return constructor.Invoke(parameters)
End If
End If

Return Nothing
End Function
#End If
End Module
End Namespace
@@ -0,0 +1,61 @@
Imports System
Imports System.Web.Http
Imports System.Web.Mvc
Imports accessAPI.Areas.HelpPage.Models
Imports accessAPI.Areas.HelpPage.ModelDescriptions

Namespace Areas.HelpPage.Controllers
''' <summary>
''' The controller that will handle requests for the help page.
''' </summary>
Public Class HelpController
Inherits Controller

Private Const ErrorViewName As String = "Error"
Private httpConfiguration As HttpConfiguration

Public Sub New()
Me.New(GlobalConfiguration.Configuration)
End Sub

Public Sub New(config As HttpConfiguration)
Configuration = config
End Sub

Public Property Configuration As HttpConfiguration
Get
Return httpConfiguration
End Get
Private Set(value As HttpConfiguration)
httpConfiguration = value
End Set
End Property

Public Function Index() As ActionResult
ViewData("DocumentationProvider") = Configuration.Services.GetDocumentationProvider()
Return View(Configuration.Services.GetApiExplorer().ApiDescriptions)
End Function

Public Function Api(apiId As String) As ActionResult
If (Not String.IsNullOrEmpty(apiId)) Then
Dim apiModel As HelpPageApiModel = Configuration.GetHelpPageApiModel(apiId)
If (Not apiModel Is Nothing) Then
Return View(apiModel)
End If
End If
Return View(ErrorViewName)
End Function

Public Function ResourceModel(modelName As String) As ActionResult
If Not [String].IsNullOrEmpty(modelName) Then
Dim modelDescriptionGenerator As ModelDescriptionGenerator = Configuration.GetModelDescriptionGenerator()
Dim modelDescription As ModelDescription = Nothing
If modelDescriptionGenerator.GeneratedModels.TryGetValue(modelName, modelDescription) Then
Return View(modelDescription)
End If
End If

Return View(ErrorViewName)
End Function
End Class
End Namespace
@@ -0,0 +1,134 @@
.help-page h1,
.help-page .h1,
.help-page h2,
.help-page .h2,
.help-page h3,
.help-page .h3,
#body.help-page,
.help-page-table th,
.help-page-table pre,
.help-page-table p {
font-family: "Segoe UI Light", Frutiger, "Frutiger Linotype", "Dejavu Sans", "Helvetica Neue", Arial, sans-serif;
}

.help-page pre.wrapped {
white-space: -moz-pre-wrap;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
white-space: pre-wrap;
}

.help-page .warning-message-container {
margin-top: 20px;
padding: 0 10px;
color: #525252;
background: #EFDCA9;
border: 1px solid #CCCCCC;
}

.help-page-table {
width: 100%;
border-collapse: collapse;
text-align: left;
margin: 0px 0px 20px 0px;
border-top: 1px solid #D4D4D4;
}

.help-page-table th {
text-align: left;
font-weight: bold;
border-bottom: 1px solid #D4D4D4;
padding: 5px 6px 5px 6px;
}

.help-page-table td {
border-bottom: 1px solid #D4D4D4;
padding: 10px 8px 10px 8px;
vertical-align: top;
}

.help-page-table pre,
.help-page-table p {
margin: 0px;
padding: 0px;
font-family: inherit;
font-size: 100%;
}

.help-page-table tbody tr:hover td {
background-color: #F3F3F3;
}

.help-page a:hover {
background-color: transparent;
}

.help-page .sample-header {
border: 2px solid #D4D4D4;
background: #00497E;
color: #FFFFFF;
padding: 8px 15px;
border-bottom: none;
display: inline-block;
margin: 10px 0px 0px 0px;
}

.help-page .sample-content {
display: block;
border-width: 0;
padding: 15px 20px;
background: #FFFFFF;
border: 2px solid #D4D4D4;
margin: 0px 0px 10px 0px;
}

.help-page .api-name {
width: 40%;
}

.help-page .api-documentation {
width: 60%;
}

.help-page .parameter-name {
width: 20%;
}

.help-page .parameter-documentation {
width: 40%;
}

.help-page .parameter-type {
width: 20%;
}

.help-page .parameter-annotations {
width: 20%;
}

.help-page h1,
.help-page .h1 {
font-size: 36px;
line-height: normal;
}

.help-page h2,
.help-page .h2 {
font-size: 24px;
}

.help-page h3,
.help-page .h3 {
font-size: 20px;
}

#body.help-page {
font-size: 14px;
line-height: 143%;
color: #333;
}

.help-page a {
color: #0000EE;
text-decoration: none;
}
@@ -0,0 +1,22 @@
Imports System.Web.Http
Imports System.Web.Mvc

Namespace Areas.HelpPage
Public Class HelpPageAreaRegistration
Inherits AreaRegistration

Public Overrides ReadOnly Property AreaName As String
Get
Return "HelpPage"
End Get
End Property

Public Overrides Sub RegisterArea(context As AreaRegistrationContext)
context.MapRoute(
"HelpPage_Default",
"Help/{action}/{apiId}",
New With {.Controller = "Help", .action = "Index", .apiId = UrlParameter.Optional})
HelpPageConfig.Register(GlobalConfiguration.Configuration)
End Sub
End Class
End Namespace

Large diffs are not rendered by default.

@@ -0,0 +1,15 @@
Namespace Areas.HelpPage.ModelDescriptions
Public Class CollectionModelDescription
Inherits ModelDescription
Private _elementDescription As ModelDescription

Public Property ElementDescription() As ModelDescription
Get
Return _elementDescription
End Get
Set(value As ModelDescription)
_elementDescription = value
End Set
End Property
End Class
End Namespace
@@ -0,0 +1,21 @@
Imports System.Collections.ObjectModel

Namespace Areas.HelpPage.ModelDescriptions
Public Class ComplexTypeModelDescription
Inherits ModelDescription
Private _properties As Collection(Of ParameterDescription)

Public Sub New()
Properties = New Collection(Of ParameterDescription)()
End Sub

Public Property Properties() As Collection(Of ParameterDescription)
Get
Return _properties
End Get
Private Set(value As Collection(Of ParameterDescription))
_properties = value
End Set
End Property
End Class
End Namespace
@@ -0,0 +1,5 @@
Namespace Areas.HelpPage.ModelDescriptions
Public Class DictionaryModelDescription
Inherits KeyValuePairModelDescription
End Class
End Namespace
@@ -0,0 +1,22 @@
Imports System.Collections.Generic
Imports System.Collections.ObjectModel

Namespace Areas.HelpPage.ModelDescriptions
Public Class EnumTypeModelDescription
Inherits ModelDescription
Private _values As Collection(Of EnumValueDescription)

Public Sub New()
Values = New Collection(Of EnumValueDescription)()
End Sub

Public Property Values() As Collection(Of EnumValueDescription)
Get
Return _values
End Get
Private Set(value As Collection(Of EnumValueDescription))
_values = value
End Set
End Property
End Class
End Namespace
@@ -0,0 +1,34 @@
Namespace Areas.HelpPage.ModelDescriptions
Public Class EnumValueDescription
Private _documentation As String
Private _value As String
Private _name As String

Public Property Documentation() As String
Get
Return _documentation
End Get
Set(value As String)
_documentation = value
End Set
End Property

Public Property Name() As String
Get
Return _name
End Get
Set(value As String)
_name = value
End Set
End Property

Public Property Value() As String
Get
Return _value
End Get
Set(value As String)
_value = value
End Set
End Property
End Class
End Namespace
@@ -0,0 +1,9 @@
Imports System
Imports System.Reflection

Namespace Areas.HelpPage.ModelDescriptions
Public Interface IModelDocumentationProvider
Function GetDocumentation(member As MemberInfo) As String
Function GetDocumentation(type As Type) As String
End Interface
End Namespace
@@ -0,0 +1,25 @@
Namespace Areas.HelpPage.ModelDescriptions
Public Class KeyValuePairModelDescription
Inherits ModelDescription
Private _keyModelDescription As ModelDescription
Private _valueModelDescription As ModelDescription

Public Property KeyModelDescription() As ModelDescription
Get
Return _keyModelDescription
End Get
Set(value As ModelDescription)
_keyModelDescription = value
End Set
End Property

Public Property ValueModelDescription() As ModelDescription
Get
Return _valueModelDescription
End Get
Set(value As ModelDescription)
_valueModelDescription = value
End Set
End Property
End Class
End Namespace
@@ -0,0 +1,39 @@
Imports System

Namespace Areas.HelpPage.ModelDescriptions
''' <summary>
''' Describes a type model.
''' </summary>
Public MustInherit Class ModelDescription
Private _name As String
Private _documentation As String
Private _modelType As Type

Public Property Documentation() As String
Get
Return _documentation
End Get
Set(value As String)
_documentation = value
End Set
End Property

Public Property ModelType() As Type
Get
Return _modelType
End Get
Set(value As Type)
_modelType = value
End Set
End Property

Public Property Name() As String
Get
Return _name
End Get
Set(value As String)
_name = value
End Set
End Property
End Class
End Namespace

Large diffs are not rendered by default.

@@ -0,0 +1,25 @@
Imports System

Namespace Areas.HelpPage.ModelDescriptions
''' <summary>
''' Use this attribute to change the name of the <see cref="ModelDescription"/> generated for a type.
''' </summary>
<AttributeUsage(AttributeTargets.[Class] Or AttributeTargets.Struct Or AttributeTargets.[Enum], AllowMultiple:=False, Inherited:=False)> _
Public NotInheritable Class ModelNameAttribute
Inherits Attribute
Private _name As String

Public Sub New(name As String)
_name = name
End Sub

Public Property Name() As String
Get
Return _name
End Get
Private Set(value As String)
_name = value
End Set
End Property
End Class
End Namespace
@@ -0,0 +1,34 @@
Imports System
Imports System.Globalization
Imports System.Linq
Imports System.Reflection

Namespace Areas.HelpPage.ModelDescriptions
Friend NotInheritable Class ModelNameHelper
Private Sub New()
End Sub

' Modify this to provide custom model name mapping.
Public Shared Function GetModelName(type As Type) As String
Dim modelNameAttribute As ModelNameAttribute = type.GetCustomAttribute(Of ModelNameAttribute)()
If modelNameAttribute IsNot Nothing AndAlso Not [String].IsNullOrEmpty(modelNameAttribute.Name) Then
Return modelNameAttribute.Name
End If

Dim modelName As String = type.Name
If type.IsGenericType Then
' Format the generic type name to something like: GenericOfAgurment1AndArgument2
Dim genericType As Type = type.GetGenericTypeDefinition()
Dim genericArguments As Type() = type.GetGenericArguments()
Dim genericTypeName As String = genericType.Name

' Trim the generic parameter counts from the name
genericTypeName = genericTypeName.Substring(0, genericTypeName.IndexOf("`"c))
Dim argumentTypeNames As String() = genericArguments.[Select](Function(t) GetModelName(t)).ToArray()
modelName = [String].Format(CultureInfo.InvariantCulture, "{0}Of{1}", genericTypeName, [String].Join("And", argumentTypeNames))
End If

Return modelName
End Function
End Class
End Namespace
@@ -0,0 +1,26 @@
Imports System

Namespace Areas.HelpPage.ModelDescriptions
Public Class ParameterAnnotation
Private _annotationAttribute As Attribute
Private _documentation As String

Public Property AnnotationAttribute() As Attribute
Get
Return _annotationAttribute
End Get
Set(value As Attribute)
_annotationAttribute = value
End Set
End Property

Public Property Documentation() As String
Get
Return _documentation
End Get
Set(value As String)
_documentation = value
End Set
End Property
End Class
End Namespace
@@ -0,0 +1,51 @@
Imports System.Collections.Generic
Imports System.Collections.ObjectModel

Namespace Areas.HelpPage.ModelDescriptions
Public Class ParameterDescription
Private _annotations As Collection(Of ParameterAnnotation)
Private _documentation As String
Private _name As String
Private _typeDescription As ModelDescription

Public Sub New()
Annotations = New Collection(Of ParameterAnnotation)()
End Sub

Public Property Annotations() As Collection(Of ParameterAnnotation)
Get
Return _annotations
End Get
Private Set(value As Collection(Of ParameterAnnotation))
_annotations = value
End Set
End Property

Public Property Documentation() As String
Get
Return _documentation
End Get
Set(value As String)
_documentation = value
End Set
End Property

Public Property Name() As String
Get
Return _name
End Get
Set(value As String)
_name = value
End Set
End Property

Public Property TypeDescription() As ModelDescription
Get
Return _typeDescription
End Get
Set(value As ModelDescription)
_typeDescription = value
End Set
End Property
End Class
End Namespace
@@ -0,0 +1,5 @@
Namespace Areas.HelpPage.ModelDescriptions
Public Class SimpleTypeModelDescription
Inherits ModelDescription
End Class
End Namespace
@@ -0,0 +1,163 @@
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Net.Http.Headers
Imports System.Web.Http.Description
Imports accessAPI.Areas.HelpPage.ModelDescriptions

Namespace Areas.HelpPage.Models
''' <summary>
''' The model that represents an API displayed on the help page.
''' </summary>
Public Class HelpPageApiModel
Private _sampleRequests As IDictionary(Of MediaTypeHeaderValue, Object)
Private _sampleResponses As IDictionary(Of MediaTypeHeaderValue, Object)
Private _errorMessages As Collection(Of String)
Private _apiDescription As ApiDescription
Private _uriParameters As Collection(Of ParameterDescription)
Private _requestModelDescription As ModelDescription
Private _resourceDescription As ModelDescription
Private _requestDocumentation As String

'''<summary>
''' Initializes a new instance of the <see cref="HelpPageApiModel"/> class.
''' </summary>
Public Sub New()
UriParameters = New Collection(Of ParameterDescription)
SampleRequests = New Dictionary(Of MediaTypeHeaderValue, Object)
SampleResponses = New Dictionary(Of MediaTypeHeaderValue, Object)
ErrorMessages = New Collection(Of String)
End Sub

''' <summary>
''' Gets or sets the <see cref="ApiDescription"/> that describes the API.
''' </summary>
Public Property ApiDescription As ApiDescription
Get
Return _apiDescription
End Get
Set(value As ApiDescription)
_apiDescription = value
End Set
End Property


''' <summary>
''' Gets or sets the <see cref="ParameterDescription"/> collection that describes the URI parameters for the API.
''' </summary>
Public Property UriParameters() As Collection(Of ParameterDescription)
Get
Return _uriParameters
End Get
Private Set(value As Collection(Of ParameterDescription))
_uriParameters = value
End Set
End Property

''' <summary>
''' Gets or sets the documentation for the request.
''' </summary>
Public Property RequestDocumentation() As String
Get
Return _requestDocumentation
End Get
Set(value As String)
_requestDocumentation = value
End Set
End Property

''' <summary>
''' Gets or sets the model description of the request body.
''' </summary>
Public Property RequestModelDescription() As ModelDescription
Get
Return _requestModelDescription
End Get
Set(value As ModelDescription)
_requestModelDescription = value
End Set
End Property

''' <summary>
''' Gets the request body parameter descriptions.
''' </summary>
Public ReadOnly Property RequestBodyParameters() As IList(Of ParameterDescription)
Get
Return GetParameterDescriptions(RequestModelDescription)
End Get
End Property

''' <summary>
''' Gets or sets the <see cref="ModelDescription"/> that describes the resource.
''' </summary>
Public Property ResourceDescription() As ModelDescription
Get
Return _resourceDescription
End Get
Set(value As ModelDescription)
_resourceDescription = value
End Set
End Property

''' <summary>
''' Gets the resource property descriptions.
''' </summary>
Public ReadOnly Property ResourceProperties() As IList(Of ParameterDescription)
Get
Return GetParameterDescriptions(ResourceDescription)
End Get
End Property

''' <summary>
''' Gets the sample requests associated with the API.
''' </summary>
Public Property SampleRequests As IDictionary(Of MediaTypeHeaderValue, Object)
Get
Return _sampleRequests
End Get
Private Set(value As IDictionary(Of MediaTypeHeaderValue, Object))
_sampleRequests = value
End Set
End Property

''' <summary>
''' Gets the sample responses associated with the API.
''' </summary>
Public Property SampleResponses As IDictionary(Of MediaTypeHeaderValue, Object)
Get
Return _sampleResponses
End Get
Private Set(value As IDictionary(Of MediaTypeHeaderValue, Object))
_sampleResponses = value
End Set
End Property

''' <summary>
''' Gets the error messages associated with this model.
''' </summary>
Public Property ErrorMessages As Collection(Of String)
Get
Return _errorMessages
End Get
Private Set(value As Collection(Of String))
_errorMessages = value
End Set
End Property

Private Shared Function GetParameterDescriptions(modelDescription As ModelDescription) As IList(Of ParameterDescription)
Dim complexTypeModelDescription As ComplexTypeModelDescription = TryCast(modelDescription, ComplexTypeModelDescription)
If complexTypeModelDescription IsNot Nothing Then
Return complexTypeModelDescription.Properties
End If

Dim collectionModelDescription As CollectionModelDescription = TryCast(modelDescription, CollectionModelDescription)
If collectionModelDescription IsNot Nothing Then
complexTypeModelDescription = TryCast(collectionModelDescription.ElementDescription, ComplexTypeModelDescription)
If complexTypeModelDescription IsNot Nothing Then
Return complexTypeModelDescription.Properties
End If
End If

Return Nothing
End Function
End Class
End Namespace

Large diffs are not rendered by default.

@@ -0,0 +1,184 @@
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Net.Http.Headers

Namespace Areas.HelpPage
''' <summary>
''' This is used to identify the place where the sample should be applied.
''' </summary>
Public Class HelpPageSampleKey
Private _actionName As String
Private _controllerName As String
Private _mediaType As MediaTypeHeaderValue
Private _parameterNames As HashSet(Of String)
Private _parameterType As Type
Private _sampleDirection As Nullable(Of SampleDirection)

''' <summary>
''' Creates a new <see cref="HelpPageSampleKey"/> based on media type.
''' </summary>
''' <param name="mediaType">The media type.</param>
Public Sub New(mediaType As MediaTypeHeaderValue)
If (mediaType Is Nothing) Then
Throw New ArgumentNullException("mediaType")
End If

_actionName = String.Empty
_controllerName = String.Empty
_parameterNames = New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
_mediaType = mediaType
End Sub

''' <summary>
''' Creates a new <see cref="HelpPageSampleKey"/> based on media type and CLR type.
''' </summary>
''' <param name="mediaType">The media type.</param>
''' <param name="type">The CLR type.</param>
Public Sub New(mediaType As MediaTypeHeaderValue, type As Type)
MyClass.New(mediaType)

If (type Is Nothing) Then
Throw New ArgumentNullException("type")
End If

_parameterType = type
End Sub

''' <summary>
''' Creates a new <see cref="HelpPageSampleKey"/> based on <see cref="SampleDirection"/>, controller name, action name and parameter names.
''' </summary>
''' <param name="sampleDirection">The <see cref="SampleDirection"/>.</param>
''' <param name="controllerName">Name of the controller.</param>
''' <param name="actionName">Name of the action.</param>
''' <param name="parameterNames">The parameter names.</param>
Public Sub New(sampleDirection As SampleDirection, controllerName As String, actionName As String, parameterNames As IEnumerable(Of String))
If (Not [Enum].IsDefined(GetType(SampleDirection), sampleDirection)) Then
Throw New InvalidEnumArgumentException("sampleDirection", CInt(sampleDirection), GetType(SampleDirection))
End If
If (controllerName Is Nothing) Then
Throw New ArgumentNullException("controllerName")
End If
If (actionName Is Nothing) Then
Throw New ArgumentNullException("actionName")
End If
If (parameterNames Is Nothing) Then
Throw New ArgumentNullException("parameterNames")
End If

_controllerName = controllerName
_actionName = actionName
_parameterNames = New HashSet(Of String)(parameterNames, StringComparer.OrdinalIgnoreCase)
_sampleDirection = sampleDirection
End Sub

''' <summary>
''' Creates a new <see cref="HelpPageSampleKey"/> based on media type, <see cref="SampleDirection"/>, controller name, action name and parameter names.
''' </summary>
''' <param name="mediaType">The media type.</param>
''' <param name="sampleDirection">The <see cref="SampleDirection"/>.</param>
''' <param name="controllerName">Name of the controller.</param>
''' <param name="actionName">Name of the action.</param>
''' <param name="parameterNames">The parameter names.</param>
Public Sub New(mediaType As MediaTypeHeaderValue, sampleDirection As SampleDirection, controllerName As String, actionName As String, parameterNames As IEnumerable(Of String))
MyClass.New(sampleDirection, controllerName, actionName, parameterNames)

If (mediaType Is Nothing) Then
Throw New ArgumentNullException("mediaType")
End If

_mediaType = mediaType
End Sub

''' <summary>
''' Gets the name of the controller.
''' </summary>
''' <value>
''' The name of the controller.
''' </value>
Public ReadOnly Property ControllerName As String
Get
Return _controllerName
End Get
End Property

''' <summary>
''' Gets the name of the action.
''' </summary>
''' <value>
''' The name of the action.
''' </value>
Public ReadOnly Property ActionName As String
Get
Return _actionName
End Get
End Property

''' <summary>
''' Gets the media type.
''' </summary>
''' <value>
''' The media type.
''' </value>
Public ReadOnly Property MediaType As MediaTypeHeaderValue
Get
Return _mediaType
End Get
End Property

''' <summary>
''' Gets the parameter names.
''' </summary>
Public ReadOnly Property ParameterNames As HashSet(Of String)
Get
Return _parameterNames
End Get
End Property

Public ReadOnly Property ParameterType As Type
Get
Return _parameterType
End Get
End Property

''' <summary>
''' Gets the <see cref="SampleDirection"/>.
''' </summary>
Public ReadOnly Property SampleDirection As Nullable(Of SampleDirection)
Get
Return _sampleDirection
End Get
End Property

Public Overrides Function Equals(obj As Object) As Boolean
Dim otherKey As HelpPageSampleKey = TryCast(obj, HelpPageSampleKey)
If (otherKey Is Nothing) Then
Return False
End If

Return String.Equals(ControllerName, otherKey.ControllerName, StringComparison.OrdinalIgnoreCase) And
String.Equals(ActionName, otherKey.ActionName, StringComparison.OrdinalIgnoreCase) And
(MediaType Is otherKey.MediaType Or (Not MediaType Is Nothing AndAlso MediaType.Equals(otherKey.MediaType))) And
ParameterType = otherKey.ParameterType And
SampleDirection.Equals(otherKey.SampleDirection) And
ParameterNames.SetEquals(otherKey.ParameterNames)
End Function

Public Overrides Function GetHashCode() As Integer
Dim hashCode As Integer = ControllerName.ToUpperInvariant().GetHashCode() Xor ActionName.ToUpperInvariant().GetHashCode()
If (Not MediaType Is Nothing) Then
hashCode = hashCode Xor MediaType.GetHashCode()
End If
If (SampleDirection.HasValue) Then
hashCode = hashCode Xor SampleDirection.GetHashCode()
End If
If (Not ParameterType Is Nothing) Then
hashCode = hashCode Xor ParameterType.GetHashCode()
End If
For Each parameterName As String In ParameterNames
hashCode = hashCode Xor parameterName.ToUpperInvariant().GetHashCode()
Next
Return hashCode
End Function
End Class
End Namespace
@@ -0,0 +1,44 @@
Imports System

Namespace Areas.HelpPage
''' <summary>
''' This represents an image sample on the help page. There's a display template named ImageSample associated with this class.
''' </summary>
Public Class ImageSample
Private _src As String

''' <summary>
''' Initializes a new instance of the <see cref="ImageSample"/> class.
''' </summary>
''' <param name="src">The URL of an image.</param>
Public Sub New(src As String)
If (src Is Nothing) Then
Throw New ArgumentNullException("src")
End If
Me.Src = src
End Sub

Public Property Src As String
Get
Return _src
End Get
Private Set(value As String)
_src = value
End Set
End Property

Public Overrides Function Equals(obj As Object) As Boolean
Dim other As ImageSample = TryCast(obj, ImageSample)

Return Not other Is Nothing AndAlso Src = other.Src
End Function

Public Overrides Function GetHashCode() As Integer
Return Src.GetHashCode()
End Function

Public Overrides Function ToString() As String
Return Src
End Function
End Class
End Namespace
@@ -0,0 +1,40 @@
Imports System

Namespace Areas.HelpPage
''' <summary>
''' This represents an invalid sample on the help page. There's a display template named InvalidSample associated with this class.
''' </summary>
Public Class InvalidSample
Private _errorMessage As String

Public Sub New(errorMessage As String)
If (errorMessage Is Nothing) Then
Throw New ArgumentNullException("errorMessage")
End If

Me.ErrorMessage = errorMessage
End Sub

Public Property ErrorMessage As String
Get
Return _errorMessage
End Get
Private Set(value As String)
_errorMessage = value
End Set
End Property

Public Overrides Function Equals(obj As Object) As Boolean
Dim other As InvalidSample = TryCast(obj, InvalidSample)
Return Not other Is Nothing AndAlso ErrorMessage = other.ErrorMessage
End Function

Public Overrides Function GetHashCode() As Integer
Return ErrorMessage.GetHashCode()
End Function

Public Overrides Function ToString() As String
Return ErrorMessage
End Function
End Class
End Namespace

Large diffs are not rendered by default.

@@ -0,0 +1,9 @@
Namespace Areas.HelpPage
''' <summary>
''' Indicates whether the sample is used for request or response
''' </summary>
Public Enum SampleDirection
Request = 0
Response
End Enum
End Namespace
@@ -0,0 +1,42 @@
Imports System

Namespace Areas.HelpPage
''' <summary>
''' This represents a preformatted text sample on the help page. There's a display template named TextSample associated with this class.
''' </summary>
Public Class TextSample
Private _text As String

Public Sub New(text As String)
If (text Is Nothing) Then
Throw New ArgumentNullException("text")
End If
Me.Text = text
End Sub

Public Property Text As String
Get
Return _text
End Get
Private Set(value As String)
_text = value
End Set
End Property

Public Overrides Function Equals(obj As Object) As Boolean
Equals = False
Dim other As TextSample = TryCast(obj, TextSample)
If Not (other Is Nothing) Then
Equals = (Text = other.Text)
End If
End Function

Public Overrides Function GetHashCode() As Integer
Return Text.GetHashCode()
End Function

Public Overrides Function ToString() As String
Return Text
End Function
End Class
End Namespace
@@ -0,0 +1,23 @@
@Imports System.Web.Http
@Imports System.Web.Http.Description
@Imports accessAPI.Areas.HelpPage.Models
@ModelType HelpPageApiModel

@Code
Dim description As ApiDescription = Model.ApiDescription
ViewData("Title") = description.HttpMethod.Method + " " + description.RelativePath
End Code

<link type="text/css" href="~/Areas/HelpPage/HelpPage.css" rel="stylesheet" />
<div id="body" class="help-page">
<section class="featured">
<div class="content-wrapper">
<p>
@Html.ActionLink("Help Page Home", "Index")
</p>
</div>
</section>
<section class="content-wrapper main-content clear-fix">
@Html.DisplayForModel()
</section>
</div>
@@ -0,0 +1,35 @@
@Imports System.Web.Http
@Imports System.Web.Http.Controllers
@Imports System.Web.Http.Description
@Imports accessAPI.Areas.HelpPage
@ModelType IGrouping(Of HttpControllerDescriptor, ApiDescription)

@Code
Dim controllerDocumentation As String = If(Not ViewData("DocumentationProvider") Is Nothing,
ViewData("DocumentationProvider").GetDocumentation(Model.Key),
Nothing)
End Code

<h2 id="@Model.Key.ControllerName">@Model.Key.ControllerName</h2>
@If Not controllerDocumentation Is Nothing Then
@<p>@controllerDocumentation</p>
End If
<table class="help-page-table">
<thead>
<tr><th>API</th><th>Description</th></tr>
</thead>
<tbody>
@For Each api As ApiDescription In Model
@<tr>
<td class="api-name"><a href="@Url.Action("Api", "Help", routeValues:=New With {.apiId = api.GetFriendlyId()})">@api.HttpMethod.Method @api.RelativePath</a></td>
<td class="api-documentation">
@If Not api.Documentation Is Nothing Then
@<p>@api.Documentation</p>
Else
@<p>No documentation available.</p>
End If
</td>
</tr>
Next
</tbody>
</table>
@@ -0,0 +1,5 @@
@Imports accessAPI.Areas.HelpPage.ModelDescriptions
@ModelType CollectionModelDescription
@If TypeOf Model.ElementDescription Is ComplexTypeModelDescription Then
@Html.DisplayFor(Function(m) m.ElementDescription)
End If
@@ -0,0 +1,3 @@
@Imports accessAPI.Areas.HelpPage.ModelDescriptions
@ModelType ComplexTypeModelDescription
@Html.DisplayFor(Function(m) Model.Properties, "Parameters")
@@ -0,0 +1,4 @@
@Imports accessAPI.Areas.HelpPage.ModelDescriptions
@ModelType DictionaryModelDescription
Dictionary of @Html.DisplayFor(Function(m) Model.KeyModelDescription.ModelType, "ModelDescriptionLink", New With { .modelDescription = Model.KeyModelDescription }) [key]
and @Html.DisplayFor(Function(m) Model.ValueModelDescription.ModelType, "ModelDescriptionLink", New With { .modelDescription = Model.ValueModelDescription }) [value]
@@ -0,0 +1,23 @@
@Imports accessAPI.Areas.HelpPage.ModelDescriptions
@ModelType EnumTypeModelDescription

<p>Possible enumeration values:</p>

<table class="help-page-table">
<thead>
<tr><th>Name</th><th>Value</th><th>Description</th></tr>
</thead>
<tbody>
@For Each value As EnumValueDescription In Model.Values
@<tr>
<td class="enum-name"><b>@value.Name</b></td>
<td class="enum-value">
<p>@value.Value</p>
</td>
<td class="enum-description">
<p>@value.Documentation</p>
</td>
</tr>
Next
</tbody>
</table>
@@ -0,0 +1,58 @@
@Imports System.Web.Http
@Imports System.Web.Http.Description
@Imports accessAPI.Areas.HelpPage.Models
@Imports accessAPI.Areas.HelpPage.ModelDescriptions
@ModelType HelpPageApiModel

@Code
Dim description As ApiDescription = Model.ApiDescription
End Code

<h1>@description.HttpMethod.Method @description.RelativePath</h1>
<div>
<p>@description.Documentation</p>

<h2>Request Information</h2>

<h3>URI Parameters</h3>
@Html.DisplayFor(Function(m) m.UriParameters, "Parameters")

<h3>Body Parameters</h3>

<p>@Model.RequestDocumentation</p>

@If Model.RequestModelDescription IsNot Nothing Then
@Html.DisplayFor(Function(m) m.RequestModelDescription.ModelType, "ModelDescriptionLink", New With {.modelDescription = Model.RequestModelDescription})
If Model.RequestBodyParameters IsNot Nothing Then
@Html.DisplayFor(Function(m) m.RequestBodyParameters, "Parameters")
End If
Else
@<p>None.</p>
End If

@If Model.SampleRequests.Count > 0 Then
@<h3>Request Formats</h3>
@Html.DisplayFor(Function(m) m.SampleRequests, "Samples")
End If

<h2>Response Information</h2>

<h3>Resource Description</h3>

<p>@description.ResponseDescription.Documentation</p>

@If Model.ResourceDescription IsNot Nothing Then
@Html.DisplayFor(Function(m) m.ResourceDescription.ModelType, "ModelDescriptionLink", New With {.modelDescription = Model.ResourceDescription})
If Model.ResourceProperties IsNot Nothing Then
@Html.DisplayFor(Function(m) m.ResourceProperties, "Parameters")
End If
Else
@<p>None.</p>
End If


@If Model.SampleResponses.Count > 0 Then
@<h3>Response Formats</h3>
@Html.DisplayFor(Function(m) m.SampleResponses, "Samples")
End If
</div>
@@ -0,0 +1,4 @@
@Imports accessAPI.Areas.HelpPage
@ModelType ImageSample

<img src="@Model.Src" />
@@ -0,0 +1,10 @@
@Imports accessAPI.Areas.HelpPage
@ModelType InvalidSample

@If HttpContext.Current.IsDebuggingEnabled Then
@<div class="warning-message-container">
<p>@Model.ErrorMessage</p>
</div>
Else
@<p>Sample not available.</p>
End If
@@ -0,0 +1,4 @@
@Imports accessAPI.Areas.HelpPage.ModelDescriptions
@ModelType KeyValuePairModelDescription
Pair of @Html.DisplayFor(Function(m) Model.KeyModelDescription.ModelType, "ModelDescriptionLink", New With { .modelDescription = Model.KeyModelDescription }) [key]
and @Html.DisplayFor(Function(m) Model.ValueModelDescription.ModelType, "ModelDescriptionLink", New With { .modelDescription = Model.ValueModelDescription }) [value]
@@ -0,0 +1,18 @@
@Imports accessAPI.Areas.HelpPage.ModelDescriptions
@ModelType Type
@Code
Dim modelDescription As ModelDescription = ViewBag.modelDescription
If TypeOf modelDescription Is ComplexTypeModelDescription Or TypeOf modelDescription Is EnumTypeModelDescription Then
If Model Is GetType(Object) Then
@:Object
Else
@Html.ActionLink(modelDescription.Name, "ResourceModel", "Help", New With {.modelName = modelDescription.Name}, Nothing)
End If
ElseIf TypeOf modelDescription Is CollectionModelDescription Then
Dim collectionDescription As CollectionModelDescription = DirectCast(modelDescription, CollectionModelDescription)
Dim elementDescription As ModelDescription = collectionDescription.ElementDescription
@:Collection of @Html.DisplayFor(Function(m) elementDescription.ModelType, "ModelDescriptionLink", New With {.modelDescription = elementDescription})
Else
@Html.DisplayFor(Function(m) modelDescription)
End If
End Code
@@ -0,0 +1,39 @@
@Imports System.Collections.ObjectModel
@Imports System.Web.Http.Description
@Imports System.Threading
@Imports accessAPI.Areas.HelpPage.ModelDescriptions
@ModelType IList(Of ParameterDescription)

@If Model.Count > 0 Then
@<table class="help-page-table">
<thead>
<tr><th>Name</th><th>Description</th><th>Type</th><th>Additional information</th></tr>
</thead>
<tbody>
@For Each parameter As ParameterDescription In Model
Dim modelDescription As ModelDescription = parameter.TypeDescription
@<tr>
<td class="parameter-name">@parameter.Name</td>
<td class="parameter-documentation">
<p>@parameter.Documentation</p>
</td>
<td class="parameter-type">
@Html.DisplayFor(Function(m) modelDescription.ModelType, "ModelDescriptionLink", New With {.modelDescription = modelDescription})
</td>
<td class="parameter-annotations">
@If parameter.Annotations.Count > 0 Then
@For Each annotation As ParameterAnnotation In parameter.Annotations
@<p>@annotation.Documentation</p>
Next
else
@<p>None.</p>
End If
</td>
</tr>
Next
</tbody>
</table>
Else
@<p>None.</p>
End If

@@ -0,0 +1,26 @@
@Imports System.Net.Http.Headers
@ModelType Dictionary(Of MediaTypeHeaderValue, Object)

@Code
'Group the samples into a single tab if they are the same.
Dim samples As Dictionary(Of String, Object) = Model.GroupBy(Function(pair) pair.Value).ToDictionary(
Function(pair) String.Join(", ", pair.Select(Function(m) m.Key.ToString()).ToArray()),
Function(pair) pair.Key)
Dim mediaTypes As Dictionary(Of String, Object).KeyCollection = samples.Keys
End Code
<div>
@For Each mediaType As String In mediaTypes
@<h4 class="sample-header">@mediaType</h4>
@<div class="sample-content">
<span><b>Sample:</b></span>
@Code
Dim sample As Object = samples(mediaType)
If sample Is Nothing Then
@<p>Sample not available.</p>
Else
@Html.DisplayFor(Function(s) sample)
End If
End code
</div>
Next
</div>
@@ -0,0 +1,3 @@
@Imports accessAPI.Areas.HelpPage.ModelDescriptions
@ModelType SimpleTypeModelDescription
@Model.Documentation
@@ -0,0 +1,6 @@
@Imports accessAPI.Areas.HelpPage
@ModelType TextSample

<pre class="wrapped">
@Model.Text
</pre>
@@ -0,0 +1,37 @@
@Imports System.Web.Http
@Imports System.Web.Http.Controllers
@Imports System.Web.Http.Description
@Imports System.Collections.ObjectModel
@Imports accessAPI.Areas.HelpPage
@ModelType Collection(Of ApiDescription)

@Code
ViewData("Title") = "ASP.NET Web API Help Page"

' Group APIs by controller
Dim apiGroups As ILookup(Of HttpControllerDescriptor, ApiDescription) = Model.ToLookup(Function(api) api.ActionDescriptor.ControllerDescriptor)
End Code

<link type="text/css" href="~/Areas/HelpPage/HelpPage.css" rel="stylesheet" />
<header class="help-page">
<div class="content-wrapper">
<div class="float-left">
<h1>@ViewData("Title")</h1>
</div>
</div>
</header>
<div id="body" class="help-page">
<section class="featured">
<div class="content-wrapper">
<h2>Introduction</h2>
<p>
Provide a general description of your APIs here.
</p>
</div>
</section>
<section class="content-wrapper main-content clear-fix">
@For Each group As IGrouping(Of HttpControllerDescriptor, ApiDescription) In apiGroups
@Html.DisplayFor(Function(m) group, "ApiGroup")
Next
</section>
</div>
@@ -0,0 +1,19 @@
@Imports System.Web.Http
@Imports accessAPI.Areas.HelpPage.ModelDescriptions
@ModelType ModelDescription

<link type="text/css" href="~/Areas/HelpPage/HelpPage.css" rel="stylesheet" />
<div id="body" class="help-page">
<section class="featured">
<div class="content-wrapper">
<p>
@Html.ActionLink("Help Page Home", "Index")
</p>
</div>
</section>
<h1>@Model.Name</h1>
<p>@Model.Documentation</p>
<section class="content-wrapper main-content clear-fix">
@Html.DisplayFor(Function(m) Model)
</section>
</div>
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>@ViewData("Title")</title>
@RenderSection("scripts", required:=False)
</head>
<body>
@RenderBody()
</body>
</html>
@@ -0,0 +1,41 @@
<?xml version="1.0"?>

<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>

<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
</namespaces>
</pages>
</system.web.webPages.razor>

<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>

<system.web>
<compilation debug="true">
<assemblies>
<add assembly="System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</assemblies>
</compilation>
</system.web>

<system.webServer>
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>
</configuration>
@@ -0,0 +1,4 @@
@Code
' Change the Layout path below to blend the look and feel of the help page with your existing web pages
Layout = "~/Views/Shared/_Layout.vbhtml"
End Code
@@ -0,0 +1,140 @@
Imports System
Imports System.Globalization
Imports System.Linq
Imports System.Reflection
Imports System.Web.Http.Controllers
Imports System.Web.Http.Description
Imports System.Xml.XPath
Imports accessAPI.Areas.HelpPage.ModelDescriptions

Namespace Areas.HelpPage
''' <summary>
''' A custom <see cref="IDocumentationProvider"/> that reads the API documentation from an XML documentation file.
''' </summary>
Public Class XmlDocumentationProvider
Implements IDocumentationProvider
Implements IModelDocumentationProvider

Private _documentNavigator As XPathNavigator
Private Const TypeExpression As String = "/doc/members/member[@name='T:{0}']"
Private Const MethodExpression As String = "/doc/members/member[@name='M:{0}']"
Private Const PropertyExpression As String = "/doc/members/member[@name='P:{0}']"
Private Const FieldExpression As String = "/doc/members/member[@name='F:{0}']"
Private Const ParameterExpression As String = "param[@name='{0}']"

''' <summary>
''' Initializes a new instance of the <see cref="XmlDocumentationProvider"/> class.
''' </summary>
''' <param name="documentPath">The physical path to XML document.</param>
Public Sub New(documentPath As String)
If (documentPath Is Nothing) Then
Throw New ArgumentNullException("documentPath")
End If
Dim xpath As New XPathDocument(documentPath)
_documentNavigator = xpath.CreateNavigator()
End Sub

Public Function GetDocumentation(controllerDescriptor As HttpControllerDescriptor) As String Implements IDocumentationProvider.GetDocumentation
Dim typeNode As XPathNavigator = GetTypeNode(controllerDescriptor.ControllerType)
Return GetTagValue(typeNode, "summary")
End Function

Public Function GetDocumentation(actionDescriptor As HttpActionDescriptor) As String Implements IDocumentationProvider.GetDocumentation
Dim methodNode As XPathNavigator = GetMethodNode(actionDescriptor)
Return GetTagValue(methodNode, "summary")
End Function

Public Function GetDocumentation(parameterDescriptor As HttpParameterDescriptor) As String Implements IDocumentationProvider.GetDocumentation
Dim reflectedParameterDescriptor As ReflectedHttpParameterDescriptor = TryCast(parameterDescriptor, ReflectedHttpParameterDescriptor)
If (Not reflectedParameterDescriptor Is Nothing) Then
Dim methodNode As XPathNavigator = GetMethodNode(reflectedParameterDescriptor.ActionDescriptor)
If (Not methodNode Is Nothing) Then
Dim parameterName As String = reflectedParameterDescriptor.ParameterInfo.Name
Dim parameterNode As XPathNavigator = methodNode.SelectSingleNode(String.Format(CultureInfo.InvariantCulture, ParameterExpression, parameterName))
If (Not parameterNode Is Nothing) Then
Return parameterNode.Value.Trim()
End If
End If
End If

Return Nothing
End Function

Public Function GetResponseDocumentation(actionDescriptor As HttpActionDescriptor) As String Implements IDocumentationProvider.GetResponseDocumentation
Dim methodNode As XPathNavigator = GetMethodNode(actionDescriptor)
Return GetTagValue(methodNode, "returns")
End Function

Public Function GetDocumentation(member As MemberInfo) As String Implements IModelDocumentationProvider.GetDocumentation
Dim memberName As String = [String].Format(CultureInfo.InvariantCulture, "{0}.{1}", GetTypeName(member.DeclaringType), member.Name)
Dim expression As String = If(member.MemberType = MemberTypes.Field, FieldExpression, PropertyExpression)
Dim selectExpression As String = [String].Format(CultureInfo.InvariantCulture, expression, memberName)
Dim propertyNode As XPathNavigator = _documentNavigator.SelectSingleNode(selectExpression)
Return GetTagValue(propertyNode, "summary")
End Function

Public Function GetDocumentation(type As Type) As String Implements IModelDocumentationProvider.GetDocumentation
Dim typeNode As XPathNavigator = GetTypeNode(type)
Return GetTagValue(typeNode, "summary")
End Function

Private Function GetMethodNode(actionDescriptor As HttpActionDescriptor) As XPathNavigator
Dim reflectedActionDescriptor As ReflectedHttpActionDescriptor = TryCast(actionDescriptor, ReflectedHttpActionDescriptor)
If (Not reflectedActionDescriptor Is Nothing) Then
Dim selectExpression As String = String.Format(CultureInfo.InvariantCulture, MethodExpression, GetMemberName(reflectedActionDescriptor.MethodInfo))
Return _documentNavigator.SelectSingleNode(selectExpression)
End If

Return Nothing
End Function

Private Shared Function GetMemberName(method As MethodInfo) As String
Dim name As String = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", method.DeclaringType.FullName, method.Name)
Dim parameters() As ParameterInfo = method.GetParameters()
If (parameters.Length <> 0) Then
Dim parameterTypeNames() As String = parameters.Select(Function(param) GetTypeName(param.ParameterType)).ToArray()
name += String.Format(CultureInfo.InvariantCulture, "({0})", String.Join(",", parameterTypeNames))
End If

Return name
End Function

Private Shared Function GetTagValue(parentNode As XPathNavigator, tagName As String) As String
If (Not parentNode Is Nothing) Then
Dim node As XPathNavigator = parentNode.SelectSingleNode(tagName)
If (Not node Is Nothing) Then
Return node.Value.Trim()
End If
End If

Return Nothing
End Function

Private Function GetTypeNode(type As Type) As XPathNavigator
Dim controllerTypeName As String = GetTypeName(type)
Dim selectExpression As String = [String].Format(CultureInfo.InvariantCulture, TypeExpression, controllerTypeName)
Return _documentNavigator.SelectSingleNode(selectExpression)
End Function

Private Shared Function GetTypeName(type As Type) As String
Dim name As String = type.FullName
If type.IsGenericType Then
' Format the generic type name to something like: Generic{System.Int32,System.String}
Dim genericType As Type = type.GetGenericTypeDefinition()
Dim genericArguments As Type() = type.GetGenericArguments()
Dim genericTypeName As String = genericType.FullName

' Trim the generic parameter counts from the name
genericTypeName = genericTypeName.Substring(0, genericTypeName.IndexOf("`"c))
Dim argumentTypeNames As String() = genericArguments.[Select](Function(t) GetTypeName(t)).ToArray()
name = [String].Format(CultureInfo.InvariantCulture, "{0}{{{1}}}", genericTypeName, [String].Join(",", argumentTypeNames))
End If
If type.IsNested Then
' Changing the nested type name from OuterType+InnerType to OuterType.InnerType to match the XML documentation syntax.
name = name.Replace("+", ".")
End If

Return name
End Function
End Class
End Namespace
@@ -0,0 +1,17 @@
body {
padding-top: 50px;
padding-bottom: 20px;
}

/* Set padding to keep content from hitting the edges */
.body-content {
padding-left: 15px;
padding-right: 15px;
}

/* Set width on the form input elements since they're 100% wide by default */
input,
select,
textarea {
max-width: 280px;
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -0,0 +1,9 @@
Public Class HomeController
Inherits System.Web.Mvc.Controller

Function Index() As ActionResult
ViewData("Title") = "Home Page"

Return View()
End Function
End Class
@@ -0,0 +1,33 @@
Imports System.Net
Imports System.Net.Http
Imports System.Web.Http

<Authorize>
Public Class ValuesController
Inherits ApiController

' GET api/values
Public Function GetValues() As IEnumerable(Of String)
Return New String() {"value1", "value2"}
End Function

' GET api/values/5
Public Function GetValue(id As Integer) As String
Return "value"
End Function

' POST api/values
Public Sub PostValue(<FromBody> value As String)

End Sub

' PUT api/values/5
Public Sub PutValue(id As Integer, <FromBody> value As String)

End Sub

' DELETE api/values/5
Public Sub DeleteValue(id As Integer)

End Sub
End Class
@@ -0,0 +1 @@
<%@ Application Codebehind="Global.asax.vb" Inherits="accessAPI.WebApiApplication" Language="VB" %>
@@ -0,0 +1,14 @@
Imports System.Web.Http
Imports System.Web.Optimization

Public Class WebApiApplication
Inherits System.Web.HttpApplication

Sub Application_Start()
AreaRegistration.RegisterAllAreas()
GlobalConfiguration.Configure(AddressOf WebApiConfig.Register)
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters)
RouteConfig.RegisterRoutes(RouteTable.Routes)
BundleConfig.RegisterBundles(BundleTable.Bundles)
End Sub
End Class
@@ -0,0 +1,74 @@
Imports System.ComponentModel.DataAnnotations
Imports Newtonsoft.Json

' Models used as parameters to AccountController actions.

Public Class AddExternalLoginBindingModel
<Required>
<Display(Name := "External access token")>
Public Property ExternalAccessToken As String
End Class

Public Class ChangePasswordBindingModel
<Required>
<DataType(DataType.Password)>
<Display(Name := "Current password")>
Public Property OldPassword As String

<Required>
<StringLength(100, ErrorMessage := "The {0} must be at least {2} characters long.", MinimumLength := 6)>
<DataType(DataType.Password)>
<Display(Name := "New password")>
Public Property NewPassword As String

<DataType(DataType.Password)>
<Display(Name := "Confirm new password")>
<Compare("NewPassword", ErrorMessage := "The new password and confirmation password do not match.")>
Public Property ConfirmPassword As String
End Class

Public Class RegisterBindingModel
<Required>
<Display(Name := "Email")>
Public Property Email As String

<Required>
<StringLength(100, ErrorMessage := "The {0} must be at least {2} characters long.", MinimumLength := 6)>
<DataType(DataType.Password)>
<Display(Name := "Password")>
Public Property Password As String

<DataType(DataType.Password)>
<Display(Name := "Confirm password")>
<Compare("Password", ErrorMessage := "The password and confirmation password do not match.")>
Public Property ConfirmPassword As String
End Class

Public Class RegisterExternalBindingModel
<Required>
<Display(Name := "Email")>
Public Property Email As String
End Class

Public Class RemoveLoginBindingModel
<Required>
<Display(Name := "Login provider")>
Public Property LoginProvider As String

<Required>
<Display(Name := "Provider key")>
Public Property ProviderKey As String
End Class

Public Class SetPasswordBindingModel
<Required>
<StringLength(100, ErrorMessage := "The {0} must be at least {2} characters long.", MinimumLength := 6)>
<DataType(DataType.Password)>
<Display(Name := "New password")>
Public Property NewPassword As String

<DataType(DataType.Password)>
<Display(Name := "Confirm new password")>
<Compare("NewPassword", ErrorMessage := "The new password and confirmation password do not match.")>
Public Property ConfirmPassword As String
End Class
@@ -0,0 +1,26 @@
Imports System.Collections.Generic

' Models returned by AccountController actions.
Public Class ExternalLoginViewModel
Public Property Name As String
Public Property Url As String
Public Property State As String
End Class

Public Class ManageInfoViewModel
Public Property LocalLoginProvider As String
Public Property Email As String
Public Property Logins As IEnumerable(Of UserLoginInfoViewModel)
Public Property ExternalLoginProviders As IEnumerable(Of ExternalLoginViewModel)
End Class

Public Class UserInfoViewModel
Public Property Email As String
Public Property HasRegistered As Boolean
Public Property LoginProvider As String
End Class

Public Class UserLoginInfoViewModel
Public Property LoginProvider As String
Public Property ProviderKey As String
End Class
@@ -0,0 +1,28 @@
Imports System.Security.Claims
Imports System.Threading.Tasks
Imports Microsoft.AspNet.Identity
Imports Microsoft.AspNet.Identity.EntityFramework
Imports Microsoft.AspNet.Identity.Owin

' You can add profile data for the user by adding more properties to your ApplicationUser class, please visit https://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
Public Class ApplicationUser
Inherits IdentityUser

Public Async Function GenerateUserIdentityAsync(manager As UserManager(Of ApplicationUser), authenticationType As String) As Task(Of ClaimsIdentity)
' Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
Dim userIdentity = Await manager.CreateIdentityAsync(Me, authenticationType)
' Add custom user claims here
Return userIdentity
End Function
End Class

Public Class ApplicationDbContext
Inherits IdentityDbContext(Of ApplicationUser)
Public Sub New()
MyBase.New("DefaultConnection", throwIfV1Schema:=False)
End Sub

Public Shared Function Create() As ApplicationDbContext
Return New ApplicationDbContext()
End Function
End Class
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MySubMain>false</MySubMain>
<SingleInstance>false</SingleInstance>
<ShutdownMode>0</ShutdownMode>
<EnableVisualStyles>true</EnableVisualStyles>
<AuthenticationMode>0</AuthenticationMode>
<ApplicationType>1</ApplicationType>
<SaveMySettingsOnExit>true</SaveMySettingsOnExit>
</MyApplicationData>
@@ -0,0 +1,34 @@
Imports System
Imports System.Reflection
Imports System.Runtime.InteropServices

' General Information about an assembly is controlled through the following
' set of attributes. Change these attribute values to modify the information
' associated with an assembly.

' Review the values of the assembly attributes
<Assembly: AssemblyTitle("accessAPI")>
<Assembly: AssemblyDescription("")>
<Assembly: AssemblyCompany("")>
<Assembly: AssemblyProduct("accessAPI")>
<Assembly: AssemblyCopyright("Copyright © 2018")>
<Assembly: AssemblyTrademark("")>

<Assembly: ComVisible(False)>

' The following GUID is for the ID of the typelib if this project is exposed to COM
<Assembly: Guid("f2e20918-0c56-43da-a048-b9dd37a28fbf")>

' Version information for an assembly consists of the following four values:
'
' Major Version
' Minor Version
' Build Number
' Revision
'
' You can specify all the values or you can default the Build and Revision Numbers
' by using the '*' as shown below:
' <Assembly: AssemblyVersion("1.0.*")>

<Assembly: AssemblyVersion("1.0.0.0")>
<Assembly: AssemblyFileVersion("1.0.0.0")>
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema

Version 2.0

The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.

Example:

... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>

There are any number of "resheader" rows that contain simple
name/value pairs.

Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.

The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:

Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.

mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.

mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.

mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>