Integrated pull request from rposener for SQL storage provider for WebHook registrations!

This commit is contained in:
rposener 2015-10-20 22:58:16 -06:00 коммит произвёл Henrik Frystyk Nielsen
Родитель 73f0c0d60e
Коммит 7464765a61
27 изменённых файлов: 1597 добавлений и 0 удалений

Просмотреть файл

@ -18,6 +18,7 @@
<Word>salesforce</Word>
<Word>kudu</Word>
<Word>trello</Word>
<Word>ver</Word>
<Word>你好</Word>
</Recognized>
<Deprecated/>

Просмотреть файл

@ -15,6 +15,7 @@
<Value>\.generated\.cs$</Value>
<Value>\.g\.i\.cs$</Value>
<Value>TemporaryGeneratedFile_.*\.cs$</Value>
<Value>\.Designer\.cs$</Value>
</CollectionProperty>
</ParserSettings>
</Parser>

Просмотреть файл

@ -108,6 +108,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureReceivers", "samples\A
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InstagramReceiver", "samples\InstagramReceiver\InstagramReceiver.csproj", "{3F9F62DD-C365-4FEC-A10E-5314D111EBF5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.WebHooks.Custom.SqlStorage", "src\Microsoft.AspNet.WebHooks.Custom.SqlStorage\Microsoft.AspNet.WebHooks.Custom.SqlStorage.csproj", "{EAC99E25-F698-41B2-8671-740D642781AB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.WebHooks.Custom.SqlStorage.Test", "test\Microsoft.AspNet.WebHooks.Custom.SqlStorage.Test\Microsoft.AspNet.WebHooks.Custom.SqlStorage.Test.csproj", "{CCE7ADB5-7335-4F7D-A34D-0B7CA1D3141F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
CodeAnalysis|Any CPU = CodeAnalysis|Any CPU
@ -379,6 +383,18 @@ Global
{3F9F62DD-C365-4FEC-A10E-5314D111EBF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F9F62DD-C365-4FEC-A10E-5314D111EBF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F9F62DD-C365-4FEC-A10E-5314D111EBF5}.Release|Any CPU.Build.0 = Release|Any CPU
{EAC99E25-F698-41B2-8671-740D642781AB}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU
{EAC99E25-F698-41B2-8671-740D642781AB}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU
{EAC99E25-F698-41B2-8671-740D642781AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EAC99E25-F698-41B2-8671-740D642781AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EAC99E25-F698-41B2-8671-740D642781AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EAC99E25-F698-41B2-8671-740D642781AB}.Release|Any CPU.Build.0 = Release|Any CPU
{CCE7ADB5-7335-4F7D-A34D-0B7CA1D3141F}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU
{CCE7ADB5-7335-4F7D-A34D-0B7CA1D3141F}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU
{CCE7ADB5-7335-4F7D-A34D-0B7CA1D3141F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CCE7ADB5-7335-4F7D-A34D-0B7CA1D3141F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CCE7ADB5-7335-4F7D-A34D-0B7CA1D3141F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CCE7ADB5-7335-4F7D-A34D-0B7CA1D3141F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -428,6 +444,8 @@ Global
{D6287838-8329-4349-90F1-D9CBF49EDCEA} = {9575CB90-BC4B-43BB-8AEA-82C53FDA4187}
{5DFA6EF9-2417-47AF-B8BB-424E420D9464} = {E957C8D9-B4A0-488B-838F-BAB4DE080A76}
{3F9F62DD-C365-4FEC-A10E-5314D111EBF5} = {E957C8D9-B4A0-488B-838F-BAB4DE080A76}
{EAC99E25-F698-41B2-8671-740D642781AB} = {929F44D0-A040-4DC3-A22F-4C5829C05D44}
{CCE7ADB5-7335-4F7D-A34D-0B7CA1D3141F} = {9575CB90-BC4B-43BB-8AEA-82C53FDA4187}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EnterpriseLibraryConfigurationToolBinariesPathV6 = packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8;packages\EnterpriseLibrary.TransientFaultHandling.Data.6.0.1304.1\lib\NET45

Просмотреть файл

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
</configSections>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

Просмотреть файл

@ -0,0 +1,67 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.ComponentModel;
using System.Data.Entity;
using Microsoft.AspNet.DataProtection;
using Microsoft.AspNet.WebHooks;
using Microsoft.AspNet.WebHooks.Config;
using Microsoft.AspNet.WebHooks.Diagnostics;
using Microsoft.AspNet.WebHooks.Services;
using Microsoft.AspNet.WebHooks.Storage;
using Microsoft.Framework.DependencyInjection;
namespace System.Web.Http
{
/// <summary>
/// Extension methods for <see cref="HttpConfiguration"/>.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static class HttpConfigurationExtensions
{
private const string ApplicationName = "Microsoft.AspNet.WebHooks";
private const string Purpose = "WebHookPersistence";
private const string DataProtectionKeysFolderName = "DataProtection-Keys";
/// <summary>
/// Configures a Microsoft SQL Server Storage implementation of <see cref="IWebHookStore"/>
/// which provides a persistent store for registered WebHooks used by the custom WebHooks module.
/// </summary>
/// <param name="config">The current <see cref="HttpConfiguration"/>config.</param>
public static void InitializeCustomWebHooksSqlStorage(this HttpConfiguration config)
{
if (config == null)
{
throw new ArgumentNullException("config");
}
WebHooksConfig.Initialize(config);
ILogger logger = config.DependencyResolver.GetLogger();
SettingsDictionary settings = config.DependencyResolver.GetSettings();
// We explicitly set the DB initializer to null to avoid that an existing DB is initialized wrongly.
Database.SetInitializer<WebHookContext>(null);
IDataProtectionProvider provider = GetDataProtectionProvider();
IDataProtector protector = provider.CreateProtector(Purpose);
IWebHookStore store = new SqlWebHookStore(settings, protector, logger);
CustomServices.SetStore(store);
}
/// <summary>
/// This follows the same initialization that is provided when <see cref="IDataProtectionProvider"/>
/// is initialized within ASP.NET 5.0 Dependency Injection.
/// </summary>
/// <returns>A fully initialized <see cref="IDataProtectionProvider"/>.</returns>
internal static IDataProtectionProvider GetDataProtectionProvider()
{
ServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddDataProtection();
IServiceProvider services = serviceCollection.BuildServiceProvider();
return services.GetDataProtectionProvider();
}
}
}

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),WebHooks.sln))\tools\WebHooks.settings.targets" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{EAC99E25-F698-41B2-8671-740D642781AB}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.AspNet.WebHooks</RootNamespace>
<AssemblyName>Microsoft.AspNet.WebHooks.Custom.SqlStorage</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<DocumentationFile>$(OutputPath)$(AssemblyName).xml</DocumentationFile>
<RunCodeAnalysis>$(CodeAnalysis)</RunCodeAnalysis>
<CodeAnalysisAdditionalOptions>/assemblyCompareMode:StrongNameIgnoringVersion</CodeAnalysisAdditionalOptions>
<CodeAnalysisRuleSet>..\..\FxCop.ruleset</CodeAnalysisRuleSet>
<DefineConstants>$(DefineConstants);ASPNETWEBHOOKS</DefineConstants>
<SignAssembly>false</SignAssembly>
</PropertyGroup>
<ItemGroup>
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.SqlServer.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.AspNet.Cryptography.Internal, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.Cryptography.Internal.1.0.0-beta6\lib\net451\Microsoft.AspNet.Cryptography.Internal.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.AspNet.DataProtection, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.DataProtection.1.0.0-beta6\lib\net451\Microsoft.AspNet.DataProtection.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.AspNet.DataProtection.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.DataProtection.Abstractions.1.0.0-beta6\lib\net451\Microsoft.AspNet.DataProtection.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Framework.Configuration, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Framework.Configuration.1.0.0-beta6\lib\net45\Microsoft.Framework.Configuration.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Framework.Configuration.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Framework.Configuration.Abstractions.1.0.0-beta6\lib\net45\Microsoft.Framework.Configuration.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Framework.Configuration.Binder, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Framework.Configuration.Binder.1.0.0-beta6\lib\net45\Microsoft.Framework.Configuration.Binder.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Framework.DependencyInjection, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Framework.DependencyInjection.1.0.0-beta5\lib\net45\Microsoft.Framework.DependencyInjection.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Framework.DependencyInjection.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Framework.DependencyInjection.Abstractions.1.0.0-beta6\lib\net45\Microsoft.Framework.DependencyInjection.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Framework.Logging.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Framework.Logging.Abstractions.1.0.0-beta6\lib\net45\Microsoft.Framework.Logging.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Framework.OptionsModel, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Framework.OptionsModel.1.0.0-beta6\lib\net45\Microsoft.Framework.OptionsModel.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.2\lib\net45\System.Net.Http.Formatting.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Security" />
<Reference Include="System.Web.Http, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.2\lib\net45\System.Web.Http.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\CommonAssemblyInfo.cs">
<Link>Properties\CommonAssemblyInfo.cs</Link>
</Compile>
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="Migrations\201510210452218_WebHooksInitialDb.cs" />
<Compile Include="Migrations\201510210452218_WebHooksInitialDb.Designer.cs">
<DependentUpon>201510210452218_WebHooksInitialDb.cs</DependentUpon>
</Compile>
<Compile Include="Migrations\Configuration.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\SqlStorageResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>SqlStorageResources.resx</DependentUpon>
</Compile>
<Compile Include="Storage\Registration.cs" />
<Compile Include="Storage\WebHookContext.cs" />
<Compile Include="Extensions\HttpConfigurationExtensions.cs" />
<Compile Include="WebHooks\SqlWebHookStore.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Migrations\201510210452218_WebHooksInitialDb.resx">
<DependentUpon>201510210452218_WebHooksInitialDb.cs</DependentUpon>
<ExcludeFromStyleCop>True</ExcludeFromStyleCop>
</EmbeddedResource>
<EmbeddedResource Include="Properties\SqlStorageResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>SqlStorageResources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="App.config">
<SubType>Designer</SubType>
</None>
<None Include="Microsoft.AspNet.WebHooks.Custom.SqlStorage.nuspec" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNet.WebHooks.Common\Microsoft.AspNet.WebHooks.Common.csproj">
<Project>{f7dd0935-6320-4efc-9464-d5a2d2b8c2f7}</Project>
<Name>Microsoft.AspNet.WebHooks.Common</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.AspNet.WebHooks.Custom\Microsoft.AspNet.WebHooks.Custom.csproj">
<Project>{d4d210c6-3283-4d1d-806e-8717d8f51179}</Project>
<Name>Microsoft.AspNet.WebHooks.Custom</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<CodeAnalysisDictionary Include="..\..\CustomDictionary.xml">
<Link>CustomDictionary.xml</Link>
</CodeAnalysisDictionary>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets" Condition="Exists('..\..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,20 @@
<?xml version="1.0"?>
<package >
<metadata>
<id>$id$</id>
<version>$symversion$</version>
<title>Microsoft ASP.NET Custom WebHooks SQL Module</title>
<authors>Microsoft</authors>
<owners>Microsoft, aspnet</owners>
<licenseUrl>http://www.microsoft.com/web/webpi/eula/net_library_eula_ENU.htm</licenseUrl>
<projectUrl>http://www.asp.net/</projectUrl>
<iconUrl>http://go.microsoft.com/fwlink/?LinkID=288859</iconUrl>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>
This package provides support for persisting your custom WebHooks registrations in a SQL database.
</description>
<releaseNotes></releaseNotes>
<copyright>&#169; Microsoft Corporation. All rights reserved</copyright>
<tags>Microsoft AspNet WebApi AspNetWebApi WebHooks</tags>
</metadata>
</package>

Просмотреть файл

@ -0,0 +1,29 @@
// <auto-generated />
namespace Microsoft.AspNet.WebHooks.Custom.SqlStorage.Migrations
{
using System.CodeDom.Compiler;
using System.Data.Entity.Migrations;
using System.Data.Entity.Migrations.Infrastructure;
using System.Resources;
[GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")]
public sealed partial class WebHooksInitialDb : IMigrationMetadata
{
private readonly ResourceManager Resources = new ResourceManager(typeof(WebHooksInitialDb));
string IMigrationMetadata.Id
{
get { return "201510210452218_WebHooksInitialDb"; }
}
string IMigrationMetadata.Source
{
get { return null; }
}
string IMigrationMetadata.Target
{
get { return Resources.GetString("Target"); }
}
}
}

Просмотреть файл

@ -0,0 +1,34 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Data.Entity.Migrations;
namespace Microsoft.AspNet.WebHooks.Custom.SqlStorage.Migrations
{
/// <summary>
/// Defines a <see cref="DbMigration"/> class for managing WebHook registrations.
/// </summary>
public partial class WebHooksInitialDb : DbMigration
{
/// <inheritdoc />
public override void Up()
{
CreateTable(
"WebHooks.WebHooks",
c => new
{
User = c.String(nullable: false, maxLength: 256),
Id = c.String(nullable: false, maxLength: 256),
ProtectedData = c.String(nullable: false),
RowVer = c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"),
})
.PrimaryKey(t => new { t.User, t.Id });
}
/// <inheritdoc />
public override void Down()
{
DropTable("WebHooks.WebHooks");
}
}
}

Просмотреть файл

@ -0,0 +1,126 @@
<?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.Runtime.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:import namespace="http://www.w3.org/XML/1998/namespace" />
<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" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</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" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Target" xml:space="preserve">
<value>H4sIAAAAAAAEAM1Y3W7bNhS+H7B3EHi1AamZpNiQBnKL1Em2oHUSRGl2TUvHDlGK1EgqtZ5tF3ukvUIP9W/Kf8m6ofCNRR5+5/87lP756+/w3TIVwRNow5Uck6PRIQlAxirhcjEmuZ2/OiHv3v74Q3iRpMvgoZF77eTwpDRj8mhtdkqpiR8hZWaU8lgro+Z2FKuUskTR48PDN/ToiAJCEMQKgvAul5anUD7g40TJGDKbMzFVCQhTr+NOVKIG1ywFk7EYxmTa4p+Z7Brs6A+Y/a7UZ0OCM8EZGhSBmJOASakss2ju6ScDkdVKLqIMF5i4LzJAuTkTBmo3TjvxfT06PHYe0e5gAxXnxqr0mYBHr+sQUf/4iwJN2hBiEC8w2LZwXpeBHJM7WHBjdQ3vKzydCO2Et8R61Ec4CDbLTUrsUfSniKzSbAEHbRFhrbnfQTDJhc01jCXkiCgOgtt8Jnj8AYp79RnkWOZC9P1Bj3BvZQGXbrXKQNviDua1l5h2TQK6W/Aq8cVC6mtoj62AV2HC4sJ2IcGULT+CXNjHMTn+5VcSXPIlJM1KXW2fJMfuwkNW5/h4jb6xmYB2n27V6iz9v3Xio4XYQnLOLNuiHv/+F+rv1JeHLtTvuWS6IIFjjFxrpKpiWmKXilfsOVlvzUB9r/BdjcJvIAELG5JbZi1obN+JSrPcglclIe36athtaKBlHJFqN+qOcMuwtGuaDguq7jtTR2o1LBVsBHZNDyP3dbZUBDha7fF1hrcmdnRLK75teJluIOZwyrIM898j6noliCqWnryKns9baYVBY7OGvlprW00VoXi7LlsJXHJtrKvXGXMpniTpQMxLyIZgN8rWxdwnli4FzSn3vzq5H5P6kF1cL9HVFKQtvYbWPI/KB8fLCcoE02vZa6JEnsptZLkZwTFR//yQQ7ed9jilD+Rt7Y/ZEEUfrFkbooTUi6yfTTpIpzch/BrZ1mG+SKu97TSvo8K6unffhwblXomQAMPzxBNX6lFhLKQjJ+Am8URw9LcTmDLJ52BsNW0JduOJd5f6fu411JhEPONy8z1fG+QT0/Ej08Mh/uJbwTeDXDv0G/SfUrb8+V8Ocq2+1G8dJNg5drdqet4cHk6H/cfszilbtV47W3As31dmdwsvHMRDOghp/yUqPAfDFx2Ee6WSmEA0qwNtZK7kXDXJQU/7FjUiXu6mYFmCATvTls9ZbHE7BmPKK+ADEzmKXKQzSK7kTW4xaWfGQDoTRd/fkG7XX942Vm0Ob7Jy1H4LF9BMji7AjXyfc5G0dl+uqagNEK526jJFqyKXdlgULdK1knsC1eE7hwxkglx8D2kmEMzcyIg9wUtsQ2L5CAsWFw2rbwbZnYjVsIfnnC00S02N0Z13Hwao+zLw9iuAgaFKSxAAAA==</value>
</data>
<data name="DefaultSchema" xml:space="preserve">
<value>WebHooks</value>
</data>
</root>

Просмотреть файл

@ -0,0 +1,20 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information
using System.Data.Entity.Migrations;
using Microsoft.AspNet.WebHooks.Storage;
namespace Microsoft.AspNet.WebHooks.Custom.SqlStorage.Migrations
{
internal sealed class Configuration : DbMigrationsConfiguration<WebHookContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(WebHookContext context)
{
}
}
}

Просмотреть файл

@ -0,0 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNet.WebHooks.Custom.SqlStorage.Test")]

Просмотреть файл

@ -0,0 +1,117 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Microsoft.AspNet.WebHooks.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class SqlStorageResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal SqlStorageResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.AspNet.WebHooks.Properties.SqlStorageResources", typeof(SqlStorageResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to The &apos;{0}&apos; could not be retrieved from Azure Table store: {1}.
/// </summary>
internal static string AzureStore_BadWebHook {
get {
return ResourceManager.GetString("AzureStore_BadWebHook", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to No entry was found with partition key &apos;{0}&apos; and row key &apos;{1}&apos;..
/// </summary>
internal static string AzureStore_NotFound {
get {
return ResourceManager.GetString("AzureStore_NotFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Concurrency failure during &apos;{0}&apos; operation: &apos;{1}&apos;..
/// </summary>
internal static string SqlStore_ConcurrencyError {
get {
return ResourceManager.GetString("SqlStore_ConcurrencyError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Please provide an Azure Table Storage connection string with name &apos;{0}&apos; in the configuration string section of the &apos;Web.Config&apos; file..
/// </summary>
internal static string SqlStore_NoConnectionString {
get {
return ResourceManager.GetString("SqlStore_NoConnectionString", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to General error during &apos;{0}&apos; operation: &apos;{1}&apos;..
/// </summary>
internal static string SqlStore_OperationFailed {
get {
return ResourceManager.GetString("SqlStore_OperationFailed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Operation &apos;{0}&apos; failed with error: &apos;{1}&apos;..
/// </summary>
internal static string SqlStore_SqlOperationFailed {
get {
return ResourceManager.GetString("SqlStore_SqlOperationFailed", resourceCulture);
}
}
}
}

Просмотреть файл

@ -0,0 +1,138 @@
<?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.Runtime.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:import namespace="http://www.w3.org/XML/1998/namespace" />
<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" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</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" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AzureStore_BadWebHook" xml:space="preserve">
<value>The '{0}' could not be retrieved from Azure Table store: {1}</value>
</data>
<data name="AzureStore_NotFound" xml:space="preserve">
<value>No entry was found with partition key '{0}' and row key '{1}'.</value>
</data>
<data name="SqlStore_ConcurrencyError" xml:space="preserve">
<value>Concurrency failure during '{0}' operation: '{1}'.</value>
</data>
<data name="SqlStore_NoConnectionString" xml:space="preserve">
<value>Please provide an Azure Table Storage connection string with name '{0}' in the configuration string section of the 'Web.Config' file.</value>
</data>
<data name="SqlStore_OperationFailed" xml:space="preserve">
<value>General error during '{0}' operation: '{1}'.</value>
</data>
<data name="SqlStore_SqlOperationFailed" xml:space="preserve">
<value>Operation '{0}' failed with error: '{1}'.</value>
</data>
</root>

Просмотреть файл

@ -0,0 +1,46 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.AspNet.WebHooks.Storage
{
/// <summary>
/// Defines the WebHook registration data model for rows stored in SQL.
/// </summary>
[Table("WebHooks")]
public class Registration
{
/// <summary>
/// Gets or sets the user ID for this WebHook registration.
/// </summary>
[Key]
[StringLength(256)]
[Column(Order = 0)]
public string User { get; set; }
/// <summary>
/// Gets or sets the ID of this WebHook registration.
/// </summary>
[Key]
[StringLength(256)]
[Column(Order = 1)]
public string Id { get; set; }
/// <summary>
/// Gets or sets the data included in this WebHook registration. Note that this is encrypted
/// as it contains sensitive information.
/// </summary>
[Required]
public string ProtectedData { get; set; }
/// <summary>
/// Gets or sets a unique row version.
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "This is the pattern for row version.")]
[Timestamp]
public byte[] RowVer { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,40 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information
using System;
using System.Data.Entity;
namespace Microsoft.AspNet.WebHooks.Storage
{
/// <summary>
/// Defines a <see cref="DbContext"/> which contains the set of WebHook <see cref="Registration"/> instances.
/// </summary>
public class WebHookContext : DbContext
{
internal const string ConnectionStringName = "MS_SqlStoreConnectionString";
private const string ConnectionStringNameParameter = "name=" + ConnectionStringName;
/// <summary>
/// Initializes a new instance of the <see cref="WebHookContext"/> class.
/// </summary>
public WebHookContext() : base(ConnectionStringNameParameter)
{
}
/// <summary>
/// Gets or sets the current collection of <see cref="Registration"/> instances.
/// </summary>
public virtual DbSet<Registration> Registrations { get; set; }
/// <inheritdoc />
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
if (modelBuilder == null)
{
throw new ArgumentNullException("modelBuilder");
}
modelBuilder.HasDefaultSchema("WebHooks");
}
}
}

Просмотреть файл

@ -0,0 +1,345 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Core;
using System.Data.Entity.Infrastructure;
using System.Data.SqlClient;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.DataProtection;
using Microsoft.AspNet.WebHooks.Config;
using Microsoft.AspNet.WebHooks.Diagnostics;
using Microsoft.AspNet.WebHooks.Properties;
using Microsoft.AspNet.WebHooks.Storage;
using Newtonsoft.Json;
namespace Microsoft.AspNet.WebHooks
{
/// <summary>
/// Provides an implementation of <see cref="IWebHookStore"/> storing registered WebHooks in Microsoft SQL Server.
/// </summary>
[CLSCompliant(false)]
public class SqlWebHookStore : WebHookStore
{
private readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings() { Formatting = Formatting.None };
private readonly IDataProtector _protector;
private readonly ILogger _logger;
/// <summary>
/// Initializes a new instance of the <see cref="SqlWebHookStore"/> class with the given <paramref name="settings"/>,
/// <paramref name="protector"/>, and <paramref name="logger"/>.
/// </summary>
public SqlWebHookStore(SettingsDictionary settings, IDataProtector protector, ILogger logger)
{
if (settings == null)
{
throw new ArgumentNullException("settings");
}
if (protector == null)
{
throw new ArgumentNullException("protector");
}
if (logger == null)
{
throw new ArgumentNullException("logger");
}
CheckSqlStorageConnectionString(settings);
_protector = protector;
_logger = logger;
}
/// <inheritdoc />
public override async Task<ICollection<WebHook>> GetAllWebHooksAsync(string user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
user = NormalizeKey(user);
try
{
using (var context = new WebHookContext())
{
var registrations = await context.Registrations.Where(r => r.User == user).ToArrayAsync();
var collection = new List<WebHook>();
foreach (var registration in registrations)
{
collection.Add(ConvertFromRegistration(registration));
}
return collection;
}
}
catch (Exception ex)
{
string msg = string.Format(CultureInfo.CurrentCulture, SqlStorageResources.SqlStore_OperationFailed, "Get", ex.Message);
_logger.Error(msg, ex);
throw new InvalidOperationException(msg, ex);
}
}
/// <inheritdoc />
public override async Task<WebHook> LookupWebHookAsync(string user, string id)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
if (id == null)
{
throw new ArgumentNullException("id");
}
user = NormalizeKey(user);
id = NormalizeKey(id);
try
{
using (var context = new WebHookContext())
{
var registration = await context.Registrations.Where(r => r.User == user && r.Id == id).FirstOrDefaultAsync();
if (registration != null)
{
return ConvertFromRegistration(registration);
}
return null;
}
}
catch (Exception ex)
{
string msg = string.Format(CultureInfo.CurrentCulture, SqlStorageResources.SqlStore_OperationFailed, "Lookup", ex.Message);
_logger.Error(msg, ex);
throw new InvalidOperationException(msg, ex);
}
}
/// <inheritdoc />
public override async Task<StoreResult> InsertWebHookAsync(string user, WebHook webHook)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
if (webHook == null)
{
throw new ArgumentNullException("webHook");
}
user = NormalizeKey(user);
try
{
using (var context = new WebHookContext())
{
var registration = ConvertToRegistration(user, webHook);
context.Registrations.Attach(registration);
context.Entry(registration).State = EntityState.Added;
await context.SaveChangesAsync();
}
}
catch (DbUpdateException uex)
{
string error = uex.GetBaseException().Message;
string msg = string.Format(CultureInfo.CurrentCulture, SqlStorageResources.SqlStore_SqlOperationFailed, "Insert", error);
_logger.Error(msg, uex);
return StoreResult.Conflict;
}
catch (OptimisticConcurrencyException ocex)
{
string msg = string.Format(CultureInfo.CurrentCulture, SqlStorageResources.SqlStore_ConcurrencyError, "Insert", ocex.Message);
}
catch (SqlException sqlex)
{
string msg = string.Format(CultureInfo.CurrentCulture, SqlStorageResources.SqlStore_SqlOperationFailed, "Insert", sqlex.Message);
_logger.Error(msg, sqlex);
return StoreResult.OperationError;
}
catch (Exception ex)
{
string msg = string.Format(CultureInfo.CurrentCulture, SqlStorageResources.SqlStore_OperationFailed, "Insert", ex.Message);
_logger.Error(msg, ex);
return StoreResult.InternalError;
}
return StoreResult.Success;
}
/// <inheritdoc />
public override async Task<StoreResult> UpdateWebHookAsync(string user, WebHook webHook)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
if (webHook == null)
{
throw new ArgumentNullException("webHook");
}
user = NormalizeKey(user);
try
{
using (var context = new WebHookContext())
{
var registration = await context.Registrations.Where(r => r.User == user && r.Id == webHook.Id).FirstOrDefaultAsync();
if (registration == null)
{
return StoreResult.NotFound;
}
UpdateRegistrationFromWebHook(user, webHook, registration);
context.Entry(registration).State = EntityState.Modified;
await context.SaveChangesAsync();
}
}
catch (OptimisticConcurrencyException ocex)
{
string msg = string.Format(CultureInfo.CurrentCulture, SqlStorageResources.SqlStore_ConcurrencyError, "Update", ocex.Message);
_logger.Error(msg, ocex);
return StoreResult.Conflict;
}
catch (SqlException sqlex)
{
string msg = string.Format(CultureInfo.CurrentCulture, SqlStorageResources.SqlStore_SqlOperationFailed, "Update", sqlex.Message);
_logger.Error(msg, sqlex);
return StoreResult.OperationError;
}
catch (Exception ex)
{
string msg = string.Format(CultureInfo.CurrentCulture, SqlStorageResources.SqlStore_OperationFailed, "Update", ex.Message);
_logger.Error(msg, ex);
return StoreResult.InternalError;
}
return StoreResult.Success;
}
/// <inheritdoc />
public override async Task<StoreResult> DeleteWebHookAsync(string user, string id)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
if (id == null)
{
throw new ArgumentNullException("id");
}
user = NormalizeKey(user);
try
{
using (var context = new WebHookContext())
{
var match = await context.Registrations.Where(r => r.User == user && r.Id == id).FirstOrDefaultAsync();
if (match == null)
{
return StoreResult.NotFound;
}
context.Entry(match).State = EntityState.Deleted;
await context.SaveChangesAsync();
}
}
catch (OptimisticConcurrencyException ocex)
{
string msg = string.Format(CultureInfo.CurrentCulture, SqlStorageResources.SqlStore_ConcurrencyError, "Delete", ocex.Message);
_logger.Error(msg, ocex);
return StoreResult.Conflict;
}
catch (SqlException sqlex)
{
string msg = string.Format(CultureInfo.CurrentCulture, SqlStorageResources.SqlStore_SqlOperationFailed, "Delete", sqlex.Message);
_logger.Error(msg, sqlex);
return StoreResult.OperationError;
}
catch (Exception ex)
{
string msg = string.Format(CultureInfo.CurrentCulture, SqlStorageResources.SqlStore_OperationFailed, "Delete", ex.Message);
_logger.Error(msg, ex);
return StoreResult.InternalError;
}
return StoreResult.Success;
}
/// <inheritdoc />
public override async Task DeleteAllWebHooksAsync(string user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
user = NormalizeKey(user);
try
{
using (var context = new WebHookContext())
{
var matches = await context.Registrations.Where(r => r.User == user).ToArrayAsync();
foreach (var m in matches)
{
context.Entry(m).State = EntityState.Deleted;
}
await context.SaveChangesAsync();
}
}
catch (Exception ex)
{
string msg = string.Format(CultureInfo.CurrentCulture, SqlStorageResources.SqlStore_OperationFailed, "DeleteAll", ex.Message);
_logger.Error(msg, ex);
throw new InvalidOperationException(msg, ex);
}
}
internal static string CheckSqlStorageConnectionString(SettingsDictionary settings)
{
if (settings == null)
{
throw new ArgumentNullException("settings");
}
ConnectionSettings connection;
if (!settings.Connections.TryGetValue(WebHookContext.ConnectionStringName, out connection) || connection == null || string.IsNullOrEmpty(connection.ConnectionString))
{
string msg = string.Format(CultureInfo.CurrentCulture, SqlStorageResources.SqlStore_NoConnectionString, WebHookContext.ConnectionStringName);
throw new InvalidOperationException(msg);
}
return connection.ConnectionString;
}
private WebHook ConvertFromRegistration(Registration registration)
{
string content = _protector.Unprotect(registration.ProtectedData);
WebHook webHook = JsonConvert.DeserializeObject<WebHook>(content, _serializerSettings);
return webHook;
}
private Registration ConvertToRegistration(string user, WebHook webHook)
{
string content = JsonConvert.SerializeObject(webHook, _serializerSettings);
string protectedData = _protector.Protect(content);
var registration = new Registration
{
User = user,
Id = webHook.Id,
ProtectedData = protectedData
};
return registration;
}
private void UpdateRegistrationFromWebHook(string user, WebHook webHook, Registration registration)
{
registration.User = user;
registration.Id = webHook.Id;
string content = JsonConvert.SerializeObject(webHook, _serializerSettings);
string protectedData = _protector.Protect(content);
registration.ProtectedData = protectedData;
}
}
}

Просмотреть файл

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="EntityFramework" version="6.1.1" targetFramework="net451" />
<package id="Microsoft.AspNet.Cryptography.Internal" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.AspNet.DataProtection" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.AspNet.DataProtection.Abstractions" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.2" targetFramework="net451" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.2" targetFramework="net451" />
<package id="Microsoft.Framework.Configuration" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.Framework.Configuration.Abstractions" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.Framework.Configuration.Binder" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.Framework.DependencyInjection" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.Framework.DependencyInjection.Abstractions" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.Framework.Logging.Abstractions" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.Framework.OptionsModel" version="1.0.0-beta6" targetFramework="net451" />
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net451" />
</packages>

Просмотреть файл

@ -69,6 +69,7 @@
<Compile Include="WebHooks\WebHook.cs" />
<Compile Include="WebHooks\WebHookFilter.cs" />
<Compile Include="WebHooks\WebHookFilterManager.cs" />
<Compile Include="WebHooks\WebHookStore.cs" />
<Compile Include="WebHooks\WebHookUser.cs" />
<Compile Include="WebHooks\WebHookManager.cs" />
<Compile Include="WebHooks\WebHookWorkItem.cs" />

Просмотреть файл

@ -0,0 +1,88 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Microsoft.AspNet.WebHooks
{
/// <summary>
/// Provides an abstract <see cref="IWebHookStore"/> implementation which can be used to base other implementations on.
/// </summary>
public abstract class WebHookStore : IWebHookStore
{
/// <summary>
/// Initializes a new instance of the <see cref="WebHookStore"/> class.
/// </summary>
protected WebHookStore()
{
}
/// <inheritdoc />
public abstract Task<ICollection<WebHook>> GetAllWebHooksAsync(string user);
/// <inheritdoc />
public virtual async Task<ICollection<WebHook>> QueryWebHooksAsync(string user, IEnumerable<string> actions)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
if (actions == null)
{
throw new ArgumentNullException("actions");
}
ICollection<WebHook> webHooks = await GetAllWebHooksAsync(user);
ICollection<WebHook> matches = new List<WebHook>();
foreach (WebHook webHook in webHooks)
{
if (webHook.IsPaused)
{
continue;
}
foreach (string action in actions)
{
if (webHook.MatchesAction(action))
{
matches.Add(webHook);
break;
}
}
}
return matches;
}
/// <inheritdoc />
public abstract Task<WebHook> LookupWebHookAsync(string user, string id);
/// <inheritdoc />
public abstract Task<StoreResult> InsertWebHookAsync(string user, WebHook webHook);
/// <inheritdoc />
public abstract Task<StoreResult> UpdateWebHookAsync(string user, WebHook webHook);
/// <inheritdoc />
public abstract Task<StoreResult> DeleteWebHookAsync(string user, string id);
/// <inheritdoc />
public abstract Task DeleteAllWebHooksAsync(string user);
/// <summary>
/// Normalizes a given key to ensure consistent lookups.
/// </summary>
/// <param name="key">The key to normalize.</param>
/// <returns>The normalized key.</returns>
protected virtual string NormalizeKey(string key)
{
if (key == null)
{
throw new ArgumentNullException("key");
}
return key.ToLowerInvariant();
}
}
}

Просмотреть файл

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<appSettings></appSettings>
<connectionStrings>
<add name="MS_SqlStoreConnectionString" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=WebHooks-20151029053732;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>

Просмотреть файл

@ -0,0 +1,26 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Web.Http;
using Microsoft.AspNet.WebHooks.Services;
using Xunit;
namespace Microsoft.AspNet.WebHooks
{
public class HttpConfigurationExtensionsTests
{
[Fact]
public void Initialize_SetsStore()
{
// Arrange
HttpConfiguration config = new HttpConfiguration();
// Act
config.InitializeCustomWebHooksSqlStorage();
IWebHookStore actual = CustomServices.GetStore();
// Assert
Assert.IsType<SqlWebHookStore>(actual);
}
}
}

Просмотреть файл

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\xunit.runner.visualstudio.2.0.1\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\..\packages\xunit.runner.visualstudio.2.0.1\build\net20\xunit.runner.visualstudio.props')" />
<Import Project="..\..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props" Condition="Exists('..\..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props')" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),WebHooks.sln))\tools\WebHooks.settings.targets" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{CCE7ADB5-7335-4F7D-A34D-0B7CA1D3141F}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.AspNet.WebHooks</RootNamespace>
<AssemblyName>Microsoft.AspNet.WebHooks.Custom.SqlStorage.Test</AssemblyName>
<OutputPath>..\..\bin\$(Configuration)\Test\</OutputPath>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<RunCodeAnalysis>$(CodeAnalysis)</RunCodeAnalysis>
<CodeAnalysisAdditionalOptions>/assemblyCompareMode:StrongNameIgnoringVersion</CodeAnalysisAdditionalOptions>
<CodeAnalysisRuleSet>..\..\FxCopTest.ruleset</CodeAnalysisRuleSet>
<DefineConstants>$(DefineConstants);ASPNETWEBHOOKS</DefineConstants>
<SignAssembly>false</SignAssembly>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<ItemGroup>
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.SqlServer.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.AspNet.Cryptography.Internal, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.Cryptography.Internal.1.0.0-beta6\lib\net451\Microsoft.AspNet.Cryptography.Internal.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.AspNet.DataProtection, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.DataProtection.1.0.0-beta6\lib\net451\Microsoft.AspNet.DataProtection.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.AspNet.DataProtection.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.DataProtection.Abstractions.1.0.0-beta6\lib\net451\Microsoft.AspNet.DataProtection.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Framework.Configuration, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Framework.Configuration.1.0.0-beta6\lib\net45\Microsoft.Framework.Configuration.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Framework.Configuration.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Framework.Configuration.Abstractions.1.0.0-beta6\lib\net45\Microsoft.Framework.Configuration.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Framework.Configuration.Binder, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Framework.Configuration.Binder.1.0.0-beta6\lib\net45\Microsoft.Framework.Configuration.Binder.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Framework.DependencyInjection, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Framework.DependencyInjection.1.0.0-beta5\lib\net45\Microsoft.Framework.DependencyInjection.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Framework.DependencyInjection.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Framework.DependencyInjection.Abstractions.1.0.0-beta6\lib\net45\Microsoft.Framework.DependencyInjection.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Framework.Logging.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Framework.Logging.Abstractions.1.0.0-beta6\lib\net45\Microsoft.Framework.Logging.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Framework.OptionsModel, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Framework.OptionsModel.1.0.0-beta6\lib\net45\Microsoft.Framework.OptionsModel.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Moq, Version=4.2.1502.911, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<HintPath>..\..\packages\Moq.4.2.1502.0911\lib\net40\Moq.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.2\lib\net45\System.Net.Http.Formatting.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Security" />
<Reference Include="System.Web.Http, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.2\lib\net45\System.Web.Http.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="xunit.assert, Version=2.0.0.2929, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\..\packages\xunit.assert.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.assert.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="xunit.core, Version=2.0.0.2929, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\..\packages\xunit.extensibility.core.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Extensions\HttpConfigurationExtensionsTests.cs" />
<Compile Include="WebHooks\SqlWebHookStoreTests.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Src\Microsoft.AspNet.WebHooks.Common\Microsoft.AspNet.WebHooks.Common.csproj">
<Project>{f7dd0935-6320-4efc-9464-d5a2d2b8c2f7}</Project>
<Name>Microsoft.AspNet.WebHooks.Common</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Microsoft.AspNet.WebHooks.Custom.SqlStorage\Microsoft.AspNet.WebHooks.Custom.SqlStorage.csproj">
<Project>{eac99e25-f698-41b2-8671-740d642781ab}</Project>
<Name>Microsoft.AspNet.WebHooks.Custom.SqlStorage</Name>
</ProjectReference>
<ProjectReference Include="..\..\Src\Microsoft.AspNet.WebHooks.Custom\Microsoft.AspNet.WebHooks.Custom.csproj">
<Project>{d4d210c6-3283-4d1d-806e-8717d8f51179}</Project>
<Name>Microsoft.AspNet.WebHooks.Custom</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.TestUtilities\Microsoft.TestUtilities.csproj">
<Project>{608b1d09-e4de-4dba-8dbf-7758003988f0}</Project>
<Name>Microsoft.TestUtilities</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.AspNet.WebHooks.Custom.Test\Microsoft.AspNet.WebHooks.Custom.Test.csproj">
<Project>{acebdb96-642f-4b5d-8963-4f67bd927d76}</Project>
<Name>Microsoft.AspNet.WebHooks.Custom.Test</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<CodeAnalysisDictionary Include="..\..\CustomDictionary.xml">
<Link>CustomDictionary.xml</Link>
</CodeAnalysisDictionary>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<Folder Include="Storage\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props'))" />
<Error Condition="!Exists('..\..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets'))" />
<Error Condition="!Exists('..\..\packages\xunit.runner.visualstudio.2.0.1\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\xunit.runner.visualstudio.2.0.1\build\net20\xunit.runner.visualstudio.props'))" />
</Target>
<Import Project="..\..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets" Condition="Exists('..\..\packages\StyleCop.MSBuild.4.7.49.1\build\StyleCop.MSBuild.Targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
[assembly: CLSCompliant(false)]

Просмотреть файл

@ -0,0 +1,40 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Configuration;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Web.Http;
using Microsoft.AspNet.WebHooks.Services;
using Microsoft.AspNet.WebHooks.Storage;
using Xunit;
using EF = Microsoft.AspNet.WebHooks.Custom.SqlStorage.Migrations;
namespace Microsoft.AspNet.WebHooks
{
public class SqlWebHookStoreTests : WebHookStoreTest
{
public SqlWebHookStoreTests()
: base(CreateStore())
{
}
private static IWebHookStore CreateStore()
{
// Delete any existing DB
string connectionString = ConfigurationManager.ConnectionStrings[WebHookContext.ConnectionStringName].ConnectionString;
Database.Delete(connectionString);
// Initialize DB using code first migration
var dbConfig = new EF.Configuration();
var migrator = new DbMigrator(dbConfig);
migrator.Update();
HttpConfiguration config = new HttpConfiguration();
config.InitializeCustomWebHooksSqlStorage();
IWebHookStore store = CustomServices.GetStore();
Assert.IsType<SqlWebHookStore>(store);
return store;
}
}
}

Просмотреть файл

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="EntityFramework" version="6.1.1" targetFramework="net451" />
<package id="Microsoft.AspNet.Cryptography.Internal" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.AspNet.DataProtection" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.AspNet.DataProtection.Abstractions" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.2" targetFramework="net451" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.2" targetFramework="net451" />
<package id="Microsoft.Framework.Configuration" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.Framework.Configuration.Abstractions" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.Framework.Configuration.Binder" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.Framework.DependencyInjection" version="1.0.0-beta5" targetFramework="net451" />
<package id="Microsoft.Framework.DependencyInjection.Abstractions" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.Framework.Logging.Abstractions" version="1.0.0-beta6" targetFramework="net451" />
<package id="Microsoft.Framework.OptionsModel" version="1.0.0-beta6" targetFramework="net451" />
<package id="Moq" version="4.2.1502.0911" targetFramework="net45" />
<package id="StyleCop.MSBuild" version="4.7.49.1" targetFramework="net451" developmentDependency="true" />
<package id="xunit" version="2.0.0" targetFramework="net45" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net45" />
<package id="xunit.assert" version="2.0.0" targetFramework="net45" />
<package id="xunit.core" version="2.0.0" targetFramework="net45" />
<package id="xunit.extensibility.core" version="2.0.0" targetFramework="net45" />
<package id="xunit.runner.visualstudio" version="2.0.1" targetFramework="net451" />
</packages>