Migration from WCF Web API to Web API

Migration from WCF Web API to Web API
This commit is contained in:
Nick harris 2012-05-23 15:00:37 -07:00
Родитель 4252abe61b
Коммит ac72681132
89 изменённых файлов: 1480 добавлений и 2555 удалений

6
.nuget/NuGet.Config Normal file
Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<solution>
<add key="disableSourceControlIntegration" value="true" />
</solution>
</configuration>

71
.nuget/NuGet.targets Normal file
Просмотреть файл

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>
<!-- Windows specific commands -->
<NuGetToolsPath Condition=" '$(OS)' == 'Windows_NT'">$([System.IO.Path]::Combine($(SolutionDir), ".nuget"))</NuGetToolsPath>
<PackagesConfig Condition=" '$(OS)' == 'Windows_NT'">$([System.IO.Path]::Combine($(ProjectDir), "packages.config"))</PackagesConfig>
<PackagesDir Condition=" '$(OS)' == 'Windows_NT'">$([System.IO.Path]::Combine($(SolutionDir), "packages"))</PackagesDir>
<!-- We need to launch nuget.exe with the mono command if we're not on windows -->
<NuGetToolsPath Condition=" '$(OS)' != 'Windows_NT'">$(SolutionDir).nuget</NuGetToolsPath>
<PackagesConfig Condition=" '$(OS)' != 'Windows_NT' ">packages.config</PackagesConfig>
<PackagesDir Condition=" '$(OS)' != 'Windows_NT'">$(SolutionDir)packages</PackagesDir>
<!-- NuGet command -->
<NuGetExePath>$(NuGetToolsPath)\nuget.exe</NuGetExePath>
<NuGetCommand Condition=" '$(OS)' == 'Windows_NT'">"$(NuGetExePath)"</NuGetCommand>
<NuGetCommand Condition=" '$(OS)' != 'Windows_NT' ">mono --runtime=v4.0.30319 $(NuGetExePath)</NuGetCommand>
<PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir.Trim('\\'))</PackageOutputDir>
<!-- Package sources used to restore packages. By default will used the registered sources under %APPDATA%\NuGet\NuGet.Config -->
<PackageSources>""</PackageSources>
<!-- Enable the restore command to run before builds -->
<RestorePackages Condition="$(RestorePackages) == ''">false</RestorePackages>
<!-- Property that enables building a package from a project -->
<BuildPackage Condition="$(BuildPackage) == ''">false</BuildPackage>
<!-- Commands -->
<RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source $(PackageSources) -o "$(PackagesDir)"</RestoreCommand>
<BuildCommand>$(NuGetCommand) pack "$(ProjectPath)" -p Configuration=$(Configuration) -o "$(PackageOutputDir)" -symbols</BuildCommand>
<!-- Make the build depend on restore packages -->
<BuildDependsOn Condition="$(RestorePackages) == 'true'">
RestorePackages;
$(BuildDependsOn);
</BuildDependsOn>
<!-- Make the build depend on restore packages -->
<BuildDependsOn Condition="$(BuildPackage) == 'true'">
$(BuildDependsOn);
BuildPackage;
</BuildDependsOn>
</PropertyGroup>
<Target Name="CheckPrerequisites">
<!-- Raise an error if we're unable to locate nuget.exe -->
<Error Condition="!Exists('$(NuGetExePath)')" Text="Unable to locate '$(NuGetExePath)'" />
</Target>
<Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites">
<Exec Command="$(RestoreCommand)"
Condition="'$(OS)' != 'Windows_NT' And Exists('$(PackagesConfig)')" />
<Exec Command="$(RestoreCommand)"
LogStandardErrorAsError="true"
Condition="'$(OS)' == 'Windows_NT' And Exists('$(PackagesConfig)')" />
</Target>
<Target Name="BuildPackage" DependsOnTargets="CheckPrerequisites">
<Exec Command="$(BuildCommand)"
Condition=" '$(OS)' != 'Windows_NT' " />
<Exec Command="$(BuildCommand)"
LogStandardErrorAsError="true"
Condition=" '$(OS)' == 'Windows_NT' " />
</Target>
</Project>

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

@ -12,6 +12,8 @@
<AssemblyName>CloudServices.Identity.Membership</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\Source\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -35,45 +37,25 @@
<Reference Include="AspNet.SuppressFormsRedirect">
<HintPath>..\packages\aspnet.suppressformsredirect.0.0.1.4\lib\40\AspNet.SuppressFormsRedirect.dll</HintPath>
</Reference>
<Reference Include="EntityDataModel">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\EntityDataModel.dll</HintPath>
</Reference>
<Reference Include="Microsoft.ApplicationServer.Http">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.ApplicationServer.Http.dll</HintPath>
</Reference>
<Reference Include="Microsoft.ApplicationServer.HttpEnhancements">
<HintPath>..\packages\WebApi.Enhancements.0.6.0\lib\40-Full\Microsoft.ApplicationServer.HttpEnhancements.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Data.Spatial">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\Microsoft.Data.Spatial.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Json">
<HintPath>..\packages\JsonValue.0.6.0\lib\40\Microsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Net.Http.Formatting">
<HintPath>..\packages\HttpClient.0.6.0\lib\40\Microsoft.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Net.Http.Formatting.OData">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\Microsoft.Net.Http.Formatting.OData.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Runtime.Serialization.Internal">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.Runtime.Serialization.Internal.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Server.Common">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.Server.Common.dll</HintPath>
</Reference>
<Reference Include="Microsoft.ServiceModel.Internal">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.ServiceModel.Internal.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Data.OData">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\System.Data.OData.dll</HintPath>
<Reference Include="System.Json, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Json.4.0.20126.16343\lib\net40\System.Json.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http">
<HintPath>..\packages\HttpClient.0.6.0\lib\40\System.Net.Http.dll</HintPath>
<Reference Include="System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Net.Http.2.0.20126.16343\lib\net40\System.Net.Http.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.Formatting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Net.Http.Formatting.4.0.20126.16343\lib\net40\System.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Net.Http.2.0.20126.16343\lib\net40\System.Net.Http.WebRequest.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
@ -81,42 +63,47 @@
<Reference Include="System.ServiceModel.Web" />
<Reference Include="System.Web" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\AspNetWebApi.Core.4.0.20126.16343\lib\net40\System.Web.Http.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http.Common, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Web.Http.Common.4.0.20126.16343\lib\net40\System.Web.Http.Common.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http.WebHost, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\AspNetWebApi.4.0.20126.16343\lib\net40\System.Web.Http.WebHost.dll</HintPath>
</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="WebApi.Membership">
<HintPath>..\packages\WebApi.Membership.0.0.3.0\lib\40\WebApi.Membership.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ConfigurationExtensions.cs" />
<Compile Include="Constants.cs" />
<Compile Include="Properties\GlobalSuppressions.cs" />
<Compile Include="MembershipService.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Controllers\MembershipController.cs" />
<Compile Include="RouteExtensions.cs" />
<Compile Include="User.cs" />
<Compile Include="LogOn.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WebApi.Membership\System\AuthenticateAttribute.cs" />
<Compile Include="WebApi.Membership\System\ControllerFilteredMessageProcessingHandler.cs" />
<Compile Include="WebApi.Membership\System\HttpRequestMessageExtensions.cs" />
<Compile Include="WebApi.Membership\System\MembershipAuthenticationHandler.cs" />
<Compile Include="WebApi.Membership\System\PrincipalHelper.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>$(ProjectDir)..\NuGet\NuGet.exe install $(ProjectDir)packages.config -OutputDirectory $(ProjectDir)..\packages\</PreBuildEvent>
<PreBuildEvent></PreBuildEvent>
</PropertyGroup>
<Import Project="$(SolutionDir)\.nuget\nuget.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">

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

@ -16,34 +16,18 @@
namespace Microsoft.WindowsAzure.Samples.CloudServices.Identity.Membership
{
using System;
using System.Linq;
using Microsoft.ApplicationServer.Http;
using Microsoft.Net.Http;
using System.Net.Http;
using System.Web.Http;
internal static class ConfigurationExtensions
{
internal static HttpConfiguration AddDelegatingHandlers(this HttpConfiguration config, params Type[] handlers)
internal static HttpConfiguration AddDelegatingHandlers(this HttpConfiguration config, params DelegatingHandler[] handlers)
{
if (handlers != null)
handlers.ToList().ForEach(t => config.MessageHandlers.Add(t));
return config;
}
internal static HttpConfiguration AddRequestHandlers(this HttpConfiguration config)
{
var requestHandlers = config.RequestHandlers;
config.RequestHandlers = (c, e, od) =>
{
if (requestHandlers != null)
requestHandlers(c, e, od); // Original request handler
var filterAttribute = od.Attributes.Where(a => typeof(AuthenticateAttribute).IsAssignableFrom(a.GetType())).Cast<AuthenticateAttribute>().ToList();
filterAttribute.ForEach(a => c.Add(new MembershipAuthenticateUserOperationHandler()));
};
handlers.ToList().ForEach(t => config.MessageHandlers.Add(t));
}
return config;
}

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

@ -14,13 +14,14 @@
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
namespace Microsoft.WindowsAzure.Samples.CloudServices.Identity.Membership
{
using System;
using System.Net.Http;
internal abstract class FuncBasedFilterAttribute : Attribute
public static class Constants
{
public abstract Func<HttpRequestMessage, bool> Filter { get; }
public const string InvalidCredentialsMessage = "Invalid credentials.";
public const string InvalidUserInformation = "Invalid user information.";
}
}
}

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

@ -19,38 +19,30 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Identity.Membership
using System;
using System.Net;
using System.Net.Http;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Web.Http;
using System.Web.Security;
using Microsoft.ApplicationServer.Http.Dispatcher;
using Microsoft.Net.Http;
using Properties;
[ServiceContract]
[ServiceBehavior(IncludeExceptionDetailInFaults = false)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class MembershipService
public class MembershipController : ApiController
{
private readonly MembershipProvider membershipProvider;
public MembershipService()
public MembershipController()
: this(Membership.Provider)
{
}
[CLSCompliant(false)]
public MembershipService(MembershipProvider membershipProvider)
public MembershipController(MembershipProvider membershipProvider)
{
this.membershipProvider = membershipProvider ?? Membership.Provider;
}
[WebInvoke(UriTemplate = "logon", Method = "POST")]
public HttpResponseMessage LogOnUser(LogOn logOn)
[HttpPost]
public HttpResponseMessage Logon(LogOn logOn)
{
if ((logOn == null) || string.IsNullOrWhiteSpace(logOn.UserName) || string.IsNullOrWhiteSpace(logOn.Password))
{
throw WebException(Resources.InvalidCredentialsMessage, HttpStatusCode.BadRequest);
throw WebException(Constants.InvalidCredentialsMessage, HttpStatusCode.BadRequest);
}
bool isValidUser;
@ -65,19 +57,19 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Identity.Membership
if (!isValidUser)
{
throw WebException(Resources.InvalidCredentialsMessage, HttpStatusCode.Unauthorized);
throw WebException(HttpStatusCode.Unauthorized);
}
var token = this.GenerateMembershipToken(logOn.UserName);
return new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(token) };
}
[Authenticate, WebGet(UriTemplate = "username")]
public HttpResponseMessage UserName(HttpRequestMessage message)
[Authenticate, HttpGet]
public HttpResponseMessage UserName()
{
try
{
var username = message.User().Identity.Name;
var username = this.Request.User().Identity.Name;
if (username != null)
{
@ -85,7 +77,10 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Identity.Membership
if (user != null)
{
var response = new HttpResponseMessage(HttpStatusCode.OK)
{ Content = new StringContent(user.UserName) };
{
Content = new StringContent(user.UserName)
};
return response;
}
}
@ -98,14 +93,14 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Identity.Membership
}
}
[WebInvoke(UriTemplate = "users", Method = "PUT")]
public HttpResponseMessage<User> CreateUser(User user)
[HttpPut]
public HttpResponseMessage<User> Users(User user)
{
MembershipCreateStatus createStatus;
if ((user == null) || string.IsNullOrWhiteSpace(user.Name) || string.IsNullOrWhiteSpace(user.Email) || string.IsNullOrWhiteSpace(user.Password))
{
throw WebException(Resources.InvalidUserInformation, HttpStatusCode.BadRequest);
throw WebException(Constants.InvalidUserInformation, HttpStatusCode.BadRequest);
}
this.membershipProvider.CreateUser(user.Name, user.Password, user.Email, null, null, true, null, out createStatus);
@ -130,7 +125,13 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Identity.Membership
private static HttpResponseException WebException(string message, HttpStatusCode code)
{
var result = new HttpResponseException(new HttpResponseMessage(code) { Content = new StringContent(message) });
var response = new HttpResponseMessage(code);
if (!string.IsNullOrEmpty(message))
{
response.Content = new StringContent(message);
}
var result = new HttpResponseException(response);
if (code == HttpStatusCode.Unauthorized)
{
@ -139,5 +140,10 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Identity.Membership
return result;
}
private static HttpResponseException WebException(HttpStatusCode code)
{
return WebException(null, code);
}
}
}

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

@ -1,98 +0,0 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.235
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Identity.Membership.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 Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <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.WindowsAzure.Samples.CloudServices.Identity.Membership.Properties.Resou" +
"rces", typeof(Resources).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 Invalid credentials..
/// </summary>
internal static string InvalidCredentialsMessage {
get {
return ResourceManager.GetString("InvalidCredentialsMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Invalid user information..
/// </summary>
internal static string InvalidUserInformation {
get {
return ResourceManager.GetString("InvalidUserInformation", resourceCulture);
}
}
}
}

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

@ -1,126 +0,0 @@
<?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="InvalidCredentialsMessage" xml:space="preserve">
<value>Invalid credentials.</value>
</data>
<data name="InvalidUserInformation" xml:space="preserve">
<value>Invalid user information.</value>
</data>
</root>

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

@ -16,16 +16,24 @@
namespace Microsoft.WindowsAzure.Samples.CloudServices.Identity.Membership
{
using System;
using System.Net.Http;
using System.Web.Http;
using System.Web.Routing;
using Microsoft.ApplicationServer.Http;
public static class RouteExtensions
{
public static void MapAuthenticationServiceRoute(this RouteCollection routes, string prefix, params Type[] handlers)
public static void MapAuthenticationServiceRoute(this RouteCollection routes, string prefix, params DelegatingHandler[] handlers)
{
var configuration = new HttpConfiguration().AddDelegatingHandlers(handlers).AddRequestHandlers();
routes.MapServiceRoute<MembershipService>(prefix, configuration);
var currentConfiguration = GlobalConfiguration.Configuration;
// Handlers
currentConfiguration.AddDelegatingHandlers(handlers);
// Routes
routes.MapHttpRoute(
name: prefix,
routeTemplate: prefix + "/{action}",
defaults: new { Controller = "Membership" });
}
}
}
}

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

@ -14,27 +14,39 @@
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
namespace System.Net.Http
{
using System.Net.Http;
using System;
using System.Web;
using ApplicationServer.Http.Dispatcher;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.Web.Security;
internal class FuncBasedOperationHandler : HttpOperationHandler<HttpRequestMessage, HttpRequestMessage>
public class AuthenticateAttribute : AuthorizationFilterAttribute
{
private readonly FuncBasedFilterAttribute filterAttribute;
public FuncBasedOperationHandler(FuncBasedFilterAttribute filterAttribute)
: base("response")
public override void OnAuthorization(HttpActionContext actionContext)
{
this.filterAttribute = filterAttribute;
var input = actionContext.Request;
var principal = PrincipalHelper.GetPrincipalFromHttpRequest(input);
if (principal == null)
{
throw UnauthorizedException();
}
var user = Membership.GetUser(principal.Identity.Name);
if (user == null)
{
throw UnauthorizedException();
}
PrincipalHelper.SetPrincipal(input, principal);
base.OnAuthorization(actionContext);
}
protected override HttpRequestMessage OnHandle(HttpRequestMessage input)
private static Exception UnauthorizedException()
{
if (this.filterAttribute.Filter(input))
return input;
// HACK: Prevent ASP.NET Forms Authentication to redirect the user to the login page.
// This thread-safe approach adds a header with the suppression to be read on the
// OnEndRequest event of the pipelien. In order to fully support the supression you should have the ASP.NET Module
@ -42,7 +54,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
var response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
response.Headers.Add(SuppressFormsAuthenticationRedirectModule.SuppressFormsHeaderName, "true");
throw new HttpResponseException(response);
return new HttpResponseException(response);
}
}
}
}

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

@ -0,0 +1,52 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace System.Net.Http
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web.Http;
public abstract class ControllerFilteredMessageProcessingHandler : MessageProcessingHandler
{
public IList<string> ConfiguredControllers { get; set; }
protected abstract HttpRequestMessage ProcessRequestHandler(HttpRequestMessage request, CancellationToken cancellationToken);
protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken)
{
var routeData = request.GetRouteData();
var controllerName = routeData.Values.ContainsKey("controller") ?
routeData.Values["controller"].ToString() :
string.Empty;
if (this.ConfiguredControllers == null ||
this.ConfiguredControllers.Any(c => c.Equals(controllerName, StringComparison.OrdinalIgnoreCase)))
{
return this.ProcessRequestHandler(request, cancellationToken);
}
return request;
}
protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken)
{
return response;
}
}
}

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

@ -0,0 +1,65 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
// <copyright file="HttpRequestMessageExtensions.cs" company="open-source" >
// Copyright binary (c) 2011 by Johnny Halife, Juan Pablo Garcia, Mauro Krikorian, Mariano Converti,
// Damian Martinez, Nico Bello, and Ezequiel Morito
//
// Redistribution and use in source and binary forms, with or without modification, are permitted.
//
// The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// </copyright>
namespace System.Net.Http
{
using System.Security.Principal;
using System.Threading;
using System.Web;
/// <summary>
/// HttpRequestMessage extension methods.
/// </summary>
public static class HttpRequestMessageExtensions
{
/// <summary>
/// Returns the IPrincipal instance authenticated and stored by the MembershipAuthenticationHandler
/// on the ongoing request.
/// </summary>
/// <param name="message">this (request)</param>
/// <returns>IPrincipal instance authenticated and stored by the MembershipAuthenticationHandler</returns>
public static IPrincipal User(this HttpRequestMessage message)
{
if (message != null)
{
return message.Properties[MembershipAuthenticationHandler.MessagePrincipalKey] as IPrincipal;
}
if (Thread.CurrentPrincipal != null)
{
return Thread.CurrentPrincipal;
}
if (HttpContext.Current != null)
{
return HttpContext.Current.User;
}
return null;
}
}
}

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

@ -0,0 +1,93 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
// <copyright file="MembershipAuthenticationHandler.cs" company="open-source" >
// Copyright binary (c) 2011 by Johnny Halife, Juan Pablo Garcia, Mauro Krikorian, Mariano Converti,
// Damian Martinez, Nico Bello, and Ezequiel Morito
//
// Redistribution and use in source and binary forms, with or without modification, are permitted.
//
// The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// </copyright>
namespace System.Net.Http
{
using System.Threading;
using System.Web;
using System.Web.Http;
using System.Web.Security;
/// <summary>
/// Authenticates the ongoing request using Membership and Forms Authentication cookie.
/// Grabs the forms authentication ticket token from the cookie header and performs the authentication
/// due to WebApi requirement for ASP.NET we're also suppressing Forms Redirect by leveraging
/// aspnet.suppressformsredirect Package.
/// </summary>
public class MembershipAuthenticationHandler : ControllerFilteredMessageProcessingHandler
{
/// <summary>
/// Key used to stuff the Request with the authenticated principal after a
/// successful login.
/// </summary>
public const string MessagePrincipalKey = "identity.currentprincipal";
/// <summary>
/// Performs Membership Authentication of the on going request. Turns Membership authentication into mandatory.
/// </summary>
/// <param name="request">Ongoing request</param>
/// <param name="cancellationToken">Async Cancellation token</param>
/// <returns>The HTTP request message that was processed</returns>
protected override HttpRequestMessage ProcessRequestHandler(HttpRequestMessage request, CancellationToken cancellationToken)
{
try
{
var principal = PrincipalHelper.GetPrincipalFromHttpRequest(request);
if (principal == null)
{
this.Unauthorized();
}
var user = Membership.GetUser(principal.Identity.Name);
if (user == null)
{
this.Unauthorized();
}
PrincipalHelper.SetPrincipal(request, principal);
}
catch
{
this.Unauthorized();
}
return request;
}
private void Unauthorized()
{
// HACK: Prevent ASP.NET Forms Authentication to redirect the user to the login page.
// This thread-safe approach adds a header with the suppression to be read on the
// OnEndRequest event of the pipelien. In order to fully support the supression you should have the ASP.NET Module
// that does this (SuppressFormsAuthenticationRedirectModule).
var response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
response.Headers.Add(SuppressFormsAuthenticationRedirectModule.SuppressFormsHeaderName, "true");
throw new HttpResponseException(response);
}
}
}

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

@ -0,0 +1,67 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace System.Net.Http
{
using System;
using System.Security.Principal;
using System.Web.Security;
public static class PrincipalHelper
{
/// <summary>
/// Checks, extracs, and parses the SimpleWebToken from the Authentication Header.
/// </summary>
/// <param name="request">Ongoing request.</param>
/// <returns>A parsed SimpleWebToken.</returns>
internal static FormsAuthenticationTicket ExtractTicketFromHeader(HttpRequestMessage request)
{
var authorizationHeader = request.Headers.Authorization;
if (authorizationHeader != null && authorizationHeader.Scheme.Equals("Membership", StringComparison.OrdinalIgnoreCase))
{
var ticket = FormsAuthentication.Decrypt(authorizationHeader.Parameter);
if (ticket != null && !ticket.Expired)
{
return ticket;
}
}
return null;
}
internal static IPrincipal GetPrincipalFromHttpRequest(HttpRequestMessage request)
{
var ticket = PrincipalHelper.ExtractTicketFromHeader(request);
if (ticket == null)
{
return null;
}
return new GenericPrincipal(new FormsIdentity(ticket), new string[0]);
}
internal static void SetPrincipal(HttpRequestMessage request, IPrincipal principal)
{
// We authenticate the ongoing thread but also we stuff the principal on the message
// after a brief chat with Glenn Block we understood that the only way to authenticate
// a request and continue using it is to stuff it's authenticated user throught on
// the message properties.
request.Properties[MembershipAuthenticationHandler.MessagePrincipalKey] = principal;
}
}
}

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

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="aspnet.suppressformsredirect" version="0.0.1.4" />
<package id="HttpClient" version="0.6.0" />
<package id="JsonValue" version="0.6.0" />
<package id="WebApi" version="0.6.0" />
<package id="WebApi.All" version="0.6.0" />
<package id="WebApi.Enhancements" version="0.6.0" />
<package id="WebApi.Membership" version="0.0.3.0" />
<package id="WebApi.OData" version="0.6.0" />
<package id="AspNetWebApi" version="4.0.20126.16343" />
<package id="AspNetWebApi.Core" version="4.0.20126.16343" />
<package id="System.Json" version="4.0.20126.16343" />
<package id="System.Net.Http" version="2.0.20126.16343" />
<package id="System.Net.Http.Formatting" version="4.0.20126.16343" />
<package id="System.Web.Http.Common" version="4.0.20126.16343" />
<package id="WebApi.Membership" version="0.0.3.2" />
</packages>

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

@ -12,6 +12,8 @@
<AssemblyName>CloudServices.Notifications.WindowsAzure</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\Source\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -66,6 +68,7 @@
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\nuget.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">

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

@ -12,6 +12,8 @@
<AssemblyName>CloudServices.Notifications.Common</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\Source\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -45,6 +47,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\nuget.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">

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

@ -22,13 +22,17 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
{
public virtual string ApplicationId { get; set; }
public virtual string DeviceId { get; set; }
public virtual string TileId { get; set; }
public virtual string ClientId { get; set; }
public string ChannelUri { get; set; }
public string UserId { get; set; }
public string Expiry { get; set; }
public DateTime ExpirationTime { get; set; }
public string DeviceType { get; set; }
public static T To<T>(Endpoint endpoint) where T : Endpoint
{
@ -38,12 +42,14 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
var destination = Activator.CreateInstance<T>();
destination.ApplicationId = endpoint.ApplicationId;
destination.TileId = endpoint.TileId;
destination.ClientId = endpoint.ClientId;
destination.ChannelUri = endpoint.ChannelUri;
destination.DeviceId = endpoint.DeviceId;
destination.Expiry = endpoint.Expiry;
destination.UserId = endpoint.UserId;
destination.ExpirationTime = endpoint.ExpirationTime;
destination.DeviceType = endpoint.DeviceType;
return destination;
}
}
}
}

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

@ -27,8 +27,10 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
Endpoint Find(Func<Endpoint, bool> filterExpression);
Endpoint Find(string applicationId, string tileId, string clientId);
void InsertOrUpdate(Endpoint endpoint);
void Delete(string applicationId, string deviceId);
void Delete(string applicationId, string tileId, string clientId);
}
}
}

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

@ -12,6 +12,8 @@
<AssemblyName>CloudServices.Notifications.Sql</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\Source\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -32,53 +34,41 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="EntityDataModel">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\EntityDataModel.dll</HintPath>
</Reference>
<Reference Include="EntityFramework, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\EntityFramework.4.2.0.0\lib\net40\EntityFramework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.ApplicationServer.Http">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.ApplicationServer.Http.dll</HintPath>
</Reference>
<Reference Include="Microsoft.ApplicationServer.HttpEnhancements">
<HintPath>..\packages\WebApi.Enhancements.0.6.0\lib\40-Full\Microsoft.ApplicationServer.HttpEnhancements.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Data.Spatial">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\Microsoft.Data.Spatial.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Json">
<HintPath>..\packages\JsonValue.0.6.0\lib\40\Microsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Net.Http.Formatting">
<HintPath>..\packages\HttpClient.0.6.0\lib\40\Microsoft.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Net.Http.Formatting.OData">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\Microsoft.Net.Http.Formatting.OData.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Runtime.Serialization.Internal">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.Runtime.Serialization.Internal.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Server.Common">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.Server.Common.dll</HintPath>
</Reference>
<Reference Include="Microsoft.ServiceModel.Internal">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.ServiceModel.Internal.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Data.Entity" />
<Reference Include="System.Data.OData">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\System.Data.OData.dll</HintPath>
<Reference Include="System.Json, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Json.4.0.20126.16343\lib\net40\System.Json.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\HttpClient.0.6.0\lib\40\System.Net.Http.dll</HintPath>
<Reference Include="System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Net.Http.2.0.20126.16343\lib\net40\System.Net.Http.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.Formatting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Net.Http.Formatting.4.0.20126.16343\lib\net40\System.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Net.Http.2.0.20126.16343\lib\net40\System.Net.Http.WebRequest.dll</HintPath>
</Reference>
<Reference Include="System.ServiceModel" />
<Reference Include="System.ServiceModel.Activation" />
<Reference Include="System.ServiceModel.Web" />
<Reference Include="System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\AspNetWebApi.Core.4.0.20126.16343\lib\net40\System.Web.Http.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http.Common, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Web.Http.Common.4.0.20126.16343\lib\net40\System.Web.Http.Common.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
@ -106,8 +96,9 @@
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>$(ProjectDir)..\NuGet\NuGet.exe install $(ProjectDir)packages.config -OutputDirectory $(ProjectDir)..\packages\</PreBuildEvent>
<PreBuildEvent></PreBuildEvent>
</PropertyGroup>
<Import Project="$(SolutionDir)\.nuget\nuget.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">

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

@ -1,271 +0,0 @@
<StyleCopSettings Version="105">
<GlobalSettings>
<StringProperty Name="MergeSettingsFiles">NoMerge</StringProperty>
</GlobalSettings>
<Parsers>
<Parser ParserId="StyleCop.CSharp.CsParser">
<ParserSettings>
<BooleanProperty Name="AnalyzeDesignerFiles">False</BooleanProperty>
<CollectionProperty Name="GeneratedFileFilters">
<Value>\.g\.cs$</Value>
<Value>\.generated\.cs$</Value>
<Value>\.g\.i\.cs$</Value>
</CollectionProperty>
</ParserSettings>
</Parser>
</Parsers>
<Analyzers>
<Analyzer AnalyzerId="StyleCop.CSharp.NamingRules">
<AnalyzerSettings>
<CollectionProperty Name="Hungarian">
<Value>as</Value>
<Value>do</Value>
<Value>id</Value>
<Value>if</Value>
<Value>in</Value>
<Value>is</Value>
<Value>my</Value>
<Value>no</Value>
<Value>on</Value>
<Value>to</Value>
<Value>ui</Value>
</CollectionProperty>
</AnalyzerSettings>
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
<Rules>
<Rule Name="ElementsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="EnumerationItemsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationMustContainValidXml">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustHaveSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementDocumentationMustHaveSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustHaveSummaryText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementDocumentationMustHaveSummaryText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustNotHaveDefaultSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParametersMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustMatchElementParameters">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustDeclareParameterName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementReturnValueMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementReturnValueDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="VoidReturnValueMustNotBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParametersMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParametersMustBeDocumentedPartialClass">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustMatchTypeParameters">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustDeclareParameterName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PropertySummaryDocumentationMustMatchAccessors">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PropertySummaryDocumentationMustOmitSetAccessorWithRestrictedAccess">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustNotBeCopiedAndPasted">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SingleLineCommentsMustNotUseDocumentationStyleSlashes">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustNotBeEmpty">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustContainWhitespace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationMustMeetCharacterPercentage">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustMeetMinimumCharacterLength">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ConstructorSummaryDocumentationMustBeginWithStandardText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DestructorSummaryDocumentationMustBeginWithStandardText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationHeadersMustNotContainBlankLines">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="IncludedDocumentationXPathDoesNotExist">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="IncludeNodeDoesNotContainValidFileAndPath">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileMustHaveHeader">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustShowCopyright">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustHaveCopyrightText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustContainFileName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderFileNameDocumentationMustMatchFileName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustHaveValidCompanyText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.LayoutRules">
<Rules>
<Rule Name="CurlyBracketsForMultiLineStatementsMustNotShareLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="StatementMustNotBeOnSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementMustNotBeOnSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="CurlyBracketsMustNotBeOmitted">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="AllAccessorsMustBeMultiLineOrSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
</Analyzers>
</StyleCopSettings>

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

@ -41,4 +41,4 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications.Sql
}
}
}
}
}

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

@ -57,11 +57,16 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications.Sql
}
}
public Endpoint Find(string applicationId, string tileId, string clientId)
{
return this.Find(e => e.ApplicationId.Equals(applicationId) && e.TileId.Equals(tileId ?? string.Empty) && e.ClientId.Equals(clientId));
}
public void InsertOrUpdate(Endpoint endpoint)
{
using (var context = this.CreateContext())
{
var storedEndpoint = this.Find(e => e.ApplicationId.Equals(endpoint.ApplicationId) && e.DeviceId.Equals(endpoint.DeviceId));
var storedEndpoint = this.Find(endpoint.ApplicationId, endpoint.TileId, endpoint.ClientId);
if (storedEndpoint == null)
{
@ -74,7 +79,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications.Sql
// Update values
updatableEndpoint.ChannelUri = endpoint.ChannelUri;
updatableEndpoint.Expiry = endpoint.Expiry;
updatableEndpoint.ExpirationTime = endpoint.ExpirationTime;
updatableEndpoint.UserId = endpoint.UserId;
}
@ -82,16 +87,25 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications.Sql
}
}
public void Delete(string applicationId, string deviceId)
public void Delete(string applicationId, string tileId, string clientId)
{
if (string.IsNullOrWhiteSpace(applicationId))
throw new ArgumentNullException("applicationId");
if (string.IsNullOrWhiteSpace(clientId))
throw new ArgumentNullException("clientId");
using (var context = this.CreateContext())
{
var storedEndpoint = this.Find(e => e.ApplicationId.Equals(applicationId) && e.DeviceId.Equals(deviceId));
var storedEndpoint = this.Find(applicationId, tileId, clientId);
var removableEndpoint = Endpoint.To<SqlEndpointTableRow>(storedEndpoint);
context.Endpoints.Attach(removableEndpoint);
context.Endpoints.Remove(removableEndpoint);
context.SaveChanges();
if (storedEndpoint != null)
{
var removableEndpoint = Endpoint.To<SqlEndpointTableRow>(storedEndpoint);
context.Endpoints.Attach(removableEndpoint);
context.Endpoints.Remove(removableEndpoint);
context.SaveChanges();
}
}
}

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

@ -24,6 +24,9 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications.Sql
public override string ApplicationId { get; set; }
[Key, Column(Order = 1)]
public override string DeviceId { get; set; }
public override string TileId { get; set; }
[Key, Column(Order = 2)]
public override string ClientId { get; set; }
}
}

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

@ -1,10 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AspNetWebApi.Core" version="4.0.20126.16343" />
<package id="EntityFramework" version="4.2.0.0" />
<package id="HttpClient" version="0.6.0" />
<package id="JsonValue" version="0.6.0" />
<package id="WebApi" version="0.6.0" />
<package id="WebApi.All" version="0.6.0" />
<package id="WebApi.Enhancements" version="0.6.0" />
<package id="WebApi.OData" version="0.6.0" />
<package id="System.Json" version="4.0.20126.16343" />
<package id="System.Net.Http" version="2.0.20126.16343" />
<package id="System.Net.Http.Formatting" version="4.0.20126.16343" />
<package id="System.Web.Http.Common" version="4.0.20126.16343" />
</packages>

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

@ -12,6 +12,8 @@
<AssemblyName>CloudServices.Notifications</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\Source\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -35,53 +37,45 @@
<Reference Include="AspNet.SuppressFormsRedirect">
<HintPath>..\packages\aspnet.suppressformsredirect.0.0.1.4\lib\40\AspNet.SuppressFormsRedirect.dll</HintPath>
</Reference>
<Reference Include="EntityDataModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\EntityDataModel.dll</HintPath>
</Reference>
<Reference Include="Microsoft.ApplicationServer.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.ApplicationServer.Http.dll</HintPath>
</Reference>
<Reference Include="Microsoft.ApplicationServer.HttpEnhancements, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\WebApi.Enhancements.0.6.0\lib\40-Full\Microsoft.ApplicationServer.HttpEnhancements.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Data.Spatial, Version=4.99.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\Microsoft.Data.Spatial.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Json, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\JsonValue.0.6.0\lib\40\Microsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Net.Http.Formatting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\HttpClient.0.6.0\lib\40\Microsoft.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Net.Http.Formatting.OData, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\Microsoft.Net.Http.Formatting.OData.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Runtime.Serialization.Internal, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.Runtime.Serialization.Internal.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Server.Common, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.Server.Common.dll</HintPath>
</Reference>
<Reference Include="Microsoft.ServiceModel.Internal, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.ServiceModel.Internal.dll</HintPath>
</Reference>
<Reference Include="Microsoft.WindowsAzure.StorageClient, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Data.OData, Version=4.99.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\System.Data.OData.dll</HintPath>
</Reference>
<Reference Include="System.Data.Services.Client" />
<Reference Include="System.Json, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Json.4.0.20126.16343\lib\net40\System.Json.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\HttpClient.0.6.0\lib\40\System.Net.Http.dll</HintPath>
<Reference Include="System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Net.Http.2.0.20126.16343\lib\net40\System.Net.Http.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.Formatting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Net.Http.Formatting.4.0.20126.16343\lib\net40\System.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Net.Http.2.0.20126.16343\lib\net40\System.Net.Http.WebRequest.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.ServiceModel.Activation" />
<Reference Include="System.ServiceModel.Web" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\AspNetWebApi.Core.4.0.20126.16343\lib\net40\System.Web.Http.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http.Common, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Web.Http.Common.4.0.20126.16343\lib\net40\System.Web.Http.Common.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http.WebHost, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\AspNetWebApi.4.0.20126.16343\lib\net40\System.Web.Http.WebHost.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
@ -89,23 +83,18 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Constants.cs" />
<Compile Include="Security\AuthenticateEndpointAttribute.cs" />
<Compile Include="ConfigurationExtensions.cs" />
<Compile Include="Security\AuthorizeRegistrationEndpointAttribute.cs" />
<Compile Include="Security\AuthorizeManagementEndpointAttribute.cs" />
<Compile Include="Security\FuncBasedOperationHandler.cs" />
<Compile Include="Security\FuncBasedFilterAttribute.cs" />
<Compile Include="Security\FuncBasedAuthorizationFilterAttribute.cs" />
<Compile Include="Properties\GlobalSuppressions.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="RouteExtensions.cs" />
<Compile Include="NotificationServiceConfig.cs" />
<Compile Include="NotificationServiceContext.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="EndpointService.cs" />
<Compile Include="Controllers\EndpointController.cs" />
<Compile Include="WindowsAzure\DataServiceQueryExceptionExtensions.cs" />
<Compile Include="WindowsAzure\EndpointTableRow.cs" />
<Compile Include="WindowsAzure\WindowsAzureEndpointRepository.cs" />
@ -115,12 +104,6 @@
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Core\Source\Common\Common.csproj">
<Project>{0E6DD9F0-9B91-4D3F-9384-2C6B96734EE0}</Project>
@ -133,11 +116,12 @@
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>$(ProjectDir)..\NuGet\NuGet.exe install $(ProjectDir)packages.config -OutputDirectory $(ProjectDir)..\packages\</PreBuildEvent>
<PreBuildEvent></PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent></PostBuildEvent>
</PropertyGroup>
<Import Project="$(SolutionDir)\.nuget\nuget.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">

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

@ -16,34 +16,17 @@
namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
{
using System;
using System.Linq;
using Microsoft.ApplicationServer.Http;
using System.Net.Http;
using System.Web.Http;
internal static class ConfigurationExtensions
{
internal static HttpConfiguration AddDelegatingHandlers(this HttpConfiguration config, params Type[] handlers)
internal static HttpConfiguration AddDelegatingHandlers(this HttpConfiguration config, params DelegatingHandler[] handlers)
{
handlers.ToList().ForEach(t => config.MessageHandlers.Add(t));
return config;
}
internal static HttpConfiguration AddRequestHandlers(this HttpConfiguration config)
{
var requestHandlers = config.RequestHandlers;
config.RequestHandlers = (c, e, od) =>
{
if (requestHandlers != null)
requestHandlers(c, e, od); // Original request handler
var filterAttribute = od.Attributes.Where(a => typeof(FuncBasedFilterAttribute).IsAssignableFrom(a.GetType())).Cast<FuncBasedFilterAttribute>().ToList();
filterAttribute.ForEach(a => c.Add(new FuncBasedOperationHandler(a)));
};
return config;
}
}
}

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

@ -14,13 +14,16 @@
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Security
namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
{
using System;
using System.Net.Http;
internal abstract class FuncBasedFilterAttribute : Attribute
public static class Constants
{
public abstract Func<HttpRequestMessage, bool> Filter { get; }
public const string ErrorFilterExpressionCannotBeNull = "The filterExpression cannot be null.";
public const string ErrorParameterApplicationIdCannotBeNull = "Parameter applicationId cannot be null.";
public const string ErrorParameterConfigureParamCannotBeNull = "Parameter configure cannot be null";
public const string ErrorParameterClientIdCannotBeNull = "Parameter clientId cannot be null.";
public const string ErrorParameterEndpointCannotBeNull = "Parameter endpoint cannot be null.";
}
}
}

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

@ -20,33 +20,21 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Security.Principal;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Web;
using ApplicationServer.Http.Dispatcher;
using Properties;
using System.Web.Http;
[ServiceContract]
[ServiceBehavior(IncludeExceptionDetailInFaults = false)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class EndpointService
public class EndpointController : ApiController
{
protected readonly IEndpointRepository Repository;
private readonly Func<HttpRequestMessage, string> mapUsernameDelegate;
private static TimeSpan defaultEndpointExpirationTime = TimeSpan.FromDays(30);
public EndpointService()
: this(NotificationServiceContext.Current.Configuration.StorageProvider, NotificationServiceContext.Current.Configuration.MapUsername)
{
}
public EndpointService(IEndpointRepository repository)
public EndpointController(IEndpointRepository repository)
: this(repository, NotificationServiceContext.Current.Configuration.MapUsername)
{
}
public EndpointService(IEndpointRepository repository, Func<HttpRequestMessage, string> mapUsernameDelegate)
public EndpointController(IEndpointRepository repository, Func<HttpRequestMessage, string> mapUsernameDelegate)
{
if (repository == null)
throw new ArgumentNullException("repository");
@ -55,8 +43,8 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
this.mapUsernameDelegate = mapUsernameDelegate;
}
[WebGet(UriTemplate = ""), AuthenticateEndpoint, AuthorizeManagementEndpoint]
public IEnumerable<Endpoint> GetAll()
[AuthenticateEndpoint, AuthorizeManagementEndpoint]
public IEnumerable<Endpoint> Get()
{
try
{
@ -68,17 +56,17 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
}
}
[WebGet(UriTemplate = "{applicationId}/{deviceId}"), AuthenticateEndpoint, AuthorizeManagementEndpoint]
public HttpResponseMessage<Endpoint> Get(string applicationId, string deviceId)
[AuthenticateEndpoint, AuthorizeManagementEndpoint]
public HttpResponseMessage<Endpoint> Get(string applicationId, string tileId, string clientId)
{
try
{
var endpoint = this.Repository.Find(e => e.ApplicationId == applicationId && e.DeviceId == deviceId);
var endpoint = this.Repository.Find(applicationId, tileId, clientId);
if (endpoint == null)
return new HttpResponseMessage<Endpoint>(null, HttpStatusCode.NotFound);
return new HttpResponseMessage<Endpoint>(endpoint, HttpStatusCode.OK);
return new HttpResponseMessage<Endpoint>(Endpoint.To<Endpoint>(endpoint), HttpStatusCode.OK);
}
catch (Exception exception)
{
@ -86,43 +74,46 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
}
}
[WebInvoke(UriTemplate = "", Method = "PUT"), AuthenticateEndpoint, AuthorizeRegistrationEndpoint]
public HttpResponseMessage<Endpoint> Put(HttpRequestMessage<Endpoint> message)
[AuthenticateEndpoint, AuthorizeRegistrationEndpoint]
public HttpResponseMessage<Endpoint> Put(Endpoint endpoint)
{
if (message == null)
throw WebException(Resources.ErrorParameterEndpointCannotBeNull, HttpStatusCode.BadRequest);
try
{
var readTask = message.Content.ReadAsAsync();
readTask.Wait();
var endpoint = readTask.Result;
if (endpoint == null)
throw WebException(Constants.ErrorParameterEndpointCannotBeNull, HttpStatusCode.BadRequest);
// Set the username under which the app will store the channel
endpoint.UserId = this.mapUsernameDelegate(message);
endpoint.UserId = this.mapUsernameDelegate(this.Request);
if (endpoint.ExpirationTime == null || endpoint.ExpirationTime == DateTime.MinValue)
endpoint.ExpirationTime = DateTime.UtcNow.Add(defaultEndpointExpirationTime);
this.Repository.InsertOrUpdate(endpoint);
return new HttpResponseMessage<Endpoint>(endpoint, HttpStatusCode.Accepted);
}
catch (HttpResponseException)
{
throw;
}
catch (Exception exception)
{
throw WebException(exception.Message, HttpStatusCode.InternalServerError);
}
}
[WebInvoke(UriTemplate = "{applicationId}/{deviceId}", Method = "DELETE"), AuthenticateEndpoint, AuthorizeRegistrationEndpoint]
public HttpResponseMessage Delete(string applicationId, string deviceId)
[AuthenticateEndpoint, AuthorizeRegistrationEndpoint]
public HttpResponseMessage Delete(string applicationId, string tileId, string clientId)
{
if (string.IsNullOrWhiteSpace(applicationId))
throw WebException(Resources.ErrorParameterApplicationIdCannotBeNull, HttpStatusCode.BadRequest);
if (string.IsNullOrWhiteSpace(deviceId))
throw WebException(Resources.ErrorParameterDeviceIdCannotBeNull, HttpStatusCode.BadRequest);
throw WebException(Constants.ErrorParameterApplicationIdCannotBeNull, HttpStatusCode.BadRequest);
if (string.IsNullOrWhiteSpace(clientId))
throw WebException(Constants.ErrorParameterClientIdCannotBeNull, HttpStatusCode.BadRequest);
try
{
this.Repository.Delete(applicationId, deviceId);
return new HttpResponseMessage { StatusCode = HttpStatusCode.Accepted };
this.Repository.Delete(applicationId, tileId, clientId);
return new HttpResponseMessage(HttpStatusCode.Accepted);
}
catch (Exception exception)
{

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

@ -19,45 +19,36 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Web.Http.Controllers;
public class NotificationServiceConfig
{
private Func<HttpRequestMessage, bool> authenticateRequest;
private Func<HttpRequestMessage, bool> authorizeManagementRequest;
private Func<HttpRequestMessage, bool> authorizeRegistrationRequest;
private Func<HttpActionContext, bool> authenticateRequest;
private Func<HttpActionContext, bool> authorizeManagementRequest;
private Func<HttpActionContext, bool> authorizeRegistrationRequest;
private Func<HttpRequestMessage, string> mapUsername;
public NotificationServiceConfig()
{
this.DelegatingHandlers = new Type[] { };
this.DelegatingHandlers = new DelegatingHandler[] { };
}
public Func<HttpRequestMessage, bool> AuthenticateRequest
public Func<HttpActionContext, bool> AuthenticateRequest
{
get
{
return this.authenticateRequest ?? (this.authenticateRequest = DefaultAnonymousAccess);
}
get { return this.authenticateRequest ?? (this.authenticateRequest = DefaultAnonymousAccess); }
set { this.authenticateRequest = value; }
}
public Func<HttpRequestMessage, bool> AuthorizeManagementRequest
public Func<HttpActionContext, bool> AuthorizeManagementRequest
{
get
{
return this.authorizeManagementRequest ?? (this.authorizeManagementRequest = DefaultAnonymousAccess);
}
get { return this.authorizeManagementRequest ?? (this.authorizeManagementRequest = DefaultAnonymousAccess); }
set { this.authorizeManagementRequest = value; }
}
public Func<HttpRequestMessage, bool> AuthorizeRegistrationRequest
public Func<HttpActionContext, bool> AuthorizeRegistrationRequest
{
get
{
return this.authorizeRegistrationRequest ?? (this.authorizeRegistrationRequest = DefaultAnonymousAccess);
}
get { return this.authorizeRegistrationRequest ?? (this.authorizeRegistrationRequest = DefaultAnonymousAccess); }
set { this.authorizeRegistrationRequest = value; }
}
@ -72,14 +63,17 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
return this.mapUsername;
}
set { this.mapUsername = value; }
set
{
this.mapUsername = value;
}
}
public IEnumerable<Type> DelegatingHandlers { get; set; }
public IEnumerable<DelegatingHandler> DelegatingHandlers { get; set; }
public IEndpointRepository StorageProvider { get; set; }
private static bool DefaultAnonymousAccess(HttpRequestMessage message)
private static bool DefaultAnonymousAccess(HttpActionContext message)
{
// By default, return always true (anonymous user)
return true;
@ -91,4 +85,4 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
return string.Empty;
}
}
}
}

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

@ -18,8 +18,6 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
{
using System;
using Microsoft.WindowsAzure.Samples.CloudServices.Notifications.Properties;
public class NotificationServiceContext
{
private static readonly NotificationServiceContext Instance = new NotificationServiceContext();
@ -39,9 +37,9 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
public void Configure(Action<NotificationServiceConfig> configure)
{
if (configure == null)
throw new ArgumentException(Resources.ErrorParameterConfigureParamCannotBeNull, "configure");
throw new ArgumentException(Constants.ErrorParameterConfigureParamCannotBeNull, "configure");
configure(this.config);
}
}
}
}

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

@ -1,124 +0,0 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.235
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications.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 Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <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.WindowsAzure.Samples.CloudServices.Notifications.Properties.Resources", typeof(Resources).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 filterExpression cannot be null..
/// </summary>
internal static string ErrorFilterExpressionCannotBeNull {
get {
return ResourceManager.GetString("ErrorFilterExpressionCannotBeNull", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Parameter applicationId cannot be null..
/// </summary>
internal static string ErrorParameterApplicationIdCannotBeNull {
get {
return ResourceManager.GetString("ErrorParameterApplicationIdCannotBeNull", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Parameter configure cannot be null.
/// </summary>
internal static string ErrorParameterConfigureParamCannotBeNull {
get {
return ResourceManager.GetString("ErrorParameterConfigureParamCannotBeNull", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Parameter deviceId cannot be null..
/// </summary>
internal static string ErrorParameterDeviceIdCannotBeNull {
get {
return ResourceManager.GetString("ErrorParameterDeviceIdCannotBeNull", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Parameter endpoint cannot be null..
/// </summary>
internal static string ErrorParameterEndpointCannotBeNull {
get {
return ResourceManager.GetString("ErrorParameterEndpointCannotBeNull", resourceCulture);
}
}
}
}

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

@ -1,135 +0,0 @@
<?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="ErrorParameterApplicationIdCannotBeNull" xml:space="preserve">
<value>Parameter applicationId cannot be null.</value>
</data>
<data name="ErrorParameterDeviceIdCannotBeNull" xml:space="preserve">
<value>Parameter deviceId cannot be null.</value>
</data>
<data name="ErrorParameterEndpointCannotBeNull" xml:space="preserve">
<value>Parameter endpoint cannot be null.</value>
</data>
<data name="ErrorFilterExpressionCannotBeNull" xml:space="preserve">
<value>The filterExpression cannot be null.</value>
</data>
<data name="ErrorParameterConfigureParamCannotBeNull" xml:space="preserve">
<value>Parameter configure cannot be null</value>
</data>
</root>

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

@ -16,10 +16,11 @@
namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using System.Web.Routing;
using ApplicationServer.Http;
public static class RouteExtensions
{
@ -30,11 +31,35 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
routes.MapRegistrationServiceRoute(prefix, handlers);
}
public static void MapRegistrationServiceRoute(this RouteCollection routes, string prefix, params Type[] handlers)
public static void MapRegistrationServiceRoute(this RouteCollection routes, string prefix, params DelegatingHandler[] handlers)
{
var configuration = new HttpConfiguration().AddDelegatingHandlers(handlers).AddRequestHandlers();
var currentConfiguration = GlobalConfiguration.Configuration;
routes.MapServiceRoute<EndpointService>(prefix, configuration);
// Handlers
currentConfiguration.AddDelegatingHandlers(handlers);
// Register Dependencies
// NOTE: For any types that your dependency resolver does not handle,
// GetService should return null and GetServices should return an empty collection object
currentConfiguration.ServiceResolver.SetResolver(
t =>
{
if (t == typeof(EndpointController))
{
return new EndpointController(
NotificationServiceContext.Current.Configuration.StorageProvider,
NotificationServiceContext.Current.Configuration.MapUsername);
}
return null;
},
t => new List<object>());
// Routes
routes.MapHttpRoute(
name: prefix,
routeTemplate: prefix + "/{applicationId}/{clientId}/{tileId}",
defaults: new { Controller = "Endpoint", applicationId = RouteParameter.Optional, tileId = RouteParameter.Optional, clientId = RouteParameter.Optional });
}
}
}
}

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

@ -17,14 +17,13 @@
namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
{
using System;
using System.Net.Http;
using System.Web.Http.Controllers;
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
internal sealed class AuthenticateEndpointAttribute : FuncBasedFilterAttribute
internal sealed class AuthenticateEndpointAttribute : FuncBasedAuthorizationFilterAttribute
{
public override Func<HttpRequestMessage, bool> Filter
public override Func<HttpActionContext, bool> Filter
{
get { return NotificationServiceContext.Current.Configuration.AuthenticateRequest; }
}
}
}
}

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

@ -17,14 +17,13 @@
namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
{
using System;
using System.Net.Http;
using System.Web.Http.Controllers;
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
internal sealed class AuthorizeManagementEndpointAttribute : FuncBasedFilterAttribute
internal sealed class AuthorizeManagementEndpointAttribute : FuncBasedAuthorizationFilterAttribute
{
public override Func<HttpRequestMessage, bool> Filter
public override Func<HttpActionContext, bool> Filter
{
get { return NotificationServiceContext.Current.Configuration.AuthorizeManagementRequest; }
}
}
}
}

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

@ -17,12 +17,11 @@
namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
{
using System;
using System.Net.Http;
using System.Web.Http.Controllers;
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
internal sealed class AuthorizeRegistrationEndpointAttribute : FuncBasedFilterAttribute
internal sealed class AuthorizeRegistrationEndpointAttribute : FuncBasedAuthorizationFilterAttribute
{
public override Func<HttpRequestMessage, bool> Filter
public override Func<HttpActionContext, bool> Filter
{
get { return NotificationServiceContext.Current.Configuration.AuthorizeRegistrationRequest; }
}

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

@ -0,0 +1,50 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications
{
using System;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
internal abstract class FuncBasedAuthorizationFilterAttribute : AuthorizationFilterAttribute
{
public abstract Func<HttpActionContext, bool> Filter { get; }
public override void OnAuthorization(HttpActionContext actionContext)
{
if (this.Filter(actionContext))
{
base.OnAuthorization(actionContext);
}
else
{
// HACK: Prevent ASP.NET Forms Authentication to redirect the user to the login page.
// This thread-safe approach adds a header with the suppression to be read on the
// OnEndRequest event of the pipelien. In order to fully support the supression you should have the ASP.NET Module
// that does this (SuppressFormsAuthenticationRedirectModule).
var response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.Headers.Add(SuppressFormsAuthenticationRedirectModule.SuppressFormsHeaderName, "true");
throw new HttpResponseException(response);
}
}
}
}

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

@ -1,271 +0,0 @@
<StyleCopSettings Version="105">
<GlobalSettings>
<StringProperty Name="MergeSettingsFiles">NoMerge</StringProperty>
</GlobalSettings>
<Parsers>
<Parser ParserId="StyleCop.CSharp.CsParser">
<ParserSettings>
<BooleanProperty Name="AnalyzeDesignerFiles">False</BooleanProperty>
<CollectionProperty Name="GeneratedFileFilters">
<Value>\.g\.cs$</Value>
<Value>\.generated\.cs$</Value>
<Value>\.g\.i\.cs$</Value>
</CollectionProperty>
</ParserSettings>
</Parser>
</Parsers>
<Analyzers>
<Analyzer AnalyzerId="StyleCop.CSharp.NamingRules">
<AnalyzerSettings>
<CollectionProperty Name="Hungarian">
<Value>as</Value>
<Value>do</Value>
<Value>id</Value>
<Value>if</Value>
<Value>in</Value>
<Value>is</Value>
<Value>my</Value>
<Value>no</Value>
<Value>on</Value>
<Value>to</Value>
<Value>ui</Value>
</CollectionProperty>
</AnalyzerSettings>
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
<Rules>
<Rule Name="ElementsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="EnumerationItemsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationMustContainValidXml">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustHaveSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementDocumentationMustHaveSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustHaveSummaryText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementDocumentationMustHaveSummaryText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustNotHaveDefaultSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParametersMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustMatchElementParameters">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustDeclareParameterName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementReturnValueMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementReturnValueDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="VoidReturnValueMustNotBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParametersMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParametersMustBeDocumentedPartialClass">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustMatchTypeParameters">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustDeclareParameterName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PropertySummaryDocumentationMustMatchAccessors">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PropertySummaryDocumentationMustOmitSetAccessorWithRestrictedAccess">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustNotBeCopiedAndPasted">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SingleLineCommentsMustNotUseDocumentationStyleSlashes">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustNotBeEmpty">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustContainWhitespace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationMustMeetCharacterPercentage">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustMeetMinimumCharacterLength">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ConstructorSummaryDocumentationMustBeginWithStandardText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DestructorSummaryDocumentationMustBeginWithStandardText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationHeadersMustNotContainBlankLines">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="IncludedDocumentationXPathDoesNotExist">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="IncludeNodeDoesNotContainValidFileAndPath">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileMustHaveHeader">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustShowCopyright">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustHaveCopyrightText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustContainFileName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderFileNameDocumentationMustMatchFileName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustHaveValidCompanyText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.LayoutRules">
<Rules>
<Rule Name="CurlyBracketsForMultiLineStatementsMustNotShareLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="StatementMustNotBeOnSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementMustNotBeOnSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="CurlyBracketsMustNotBeOmitted">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="AllAccessorsMustBeMultiLineOrSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
</Analyzers>
</StyleCopSettings>

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

@ -27,4 +27,4 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications.WindowsAzur
&& ((DataServiceClientException)ex.InnerException).StatusCode == 404;
}
}
}
}

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

@ -17,13 +17,22 @@
namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications.WindowsAzure
{
using System;
using System.Data.Services.Common;
using System.Data.Services.Common;
using System.Globalization;
using System.Text;
using Microsoft.WindowsAzure.Samples.Common.Storage;
[DataServiceEntity]
[DataServiceKey(new[] { "PartitionKey", "RowKey" })]
public class EndpointTableRow : Endpoint, ITableServiceEntity
{
private string rowKey;
public EndpointTableRow()
{
this.rowKey = string.Empty;
}
public string PartitionKey
{
get { return this.ApplicationId; }
@ -32,10 +41,28 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications.WindowsAzur
public string RowKey
{
get { return this.DeviceId; }
set { this.DeviceId = value; }
get
{
if (string.IsNullOrEmpty(this.rowKey))
this.RowKey = CreateRowKey(this.TileId, this.ClientId);
return this.rowKey;
}
set
{
this.rowKey = value;
}
}
public virtual DateTime Timestamp { get; set; }
public static string CreateRowKey(string tileId, string clientId)
{
var encodedTileId = Convert.ToBase64String(Encoding.UTF8.GetBytes(tileId ?? string.Empty)).Replace("/", "%");
var encodedClientId = Convert.ToBase64String(Encoding.UTF8.GetBytes(clientId ?? string.Empty)).Replace("/", "%");
return string.Format(CultureInfo.InvariantCulture, "{0}_{1}", encodedTileId, encodedClientId);
}
}
}

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

@ -20,11 +20,12 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications.WindowsAzur
using System.Collections.Generic;
using System.Data.Services.Client;
using System.Linq;
using Common.Storage;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Samples.Common.Storage;
public class WindowsAzureEndpointRepository : IEndpointRepository
{
protected readonly IAzureTable<EndpointTableRow> Table;
protected readonly IAzureTable<EndpointTableRow> Table;
private const string EndpointsTableName = "Endpoints";
@ -77,6 +78,26 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications.WindowsAzur
return this.Endpoints.Where(filterExpression).ToList().FirstOrDefault();
}
public Endpoint Find(string applicationId, string tileId, string clientId)
{
var rowkey = EndpointTableRow.CreateRowKey(tileId, clientId);
Endpoint endpoint = null;
try
{
endpoint = this.Endpoints.Where(e => e.PartitionKey.Equals(applicationId) && e.RowKey.Equals(rowkey)).ToList().FirstOrDefault();
}
catch (DataServiceQueryException e)
{
if (e.Response.StatusCode != 404)
{
throw;
}
}
return endpoint;
}
public void InsertOrUpdate(Endpoint endpoint)
{
if (endpoint == null)
@ -85,15 +106,15 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Notifications.WindowsAzur
this.Table.AddOrUpdateEntity(Endpoint.To<EndpointTableRow>(endpoint));
}
public void Delete(string applicationId, string deviceId)
public void Delete(string applicationId, string tileId, string clientId)
{
if (applicationId == null)
if (string.IsNullOrWhiteSpace(applicationId))
throw new ArgumentNullException("applicationId");
if (deviceId == null)
throw new ArgumentNullException("deviceId");
if (string.IsNullOrWhiteSpace(clientId))
throw new ArgumentNullException("clientId");
var storedEndpoint = this.Find(e => e.ApplicationId.Equals(applicationId) && e.DeviceId.Equals(deviceId));
var storedEndpoint = this.Find(applicationId, tileId, clientId);
if (storedEndpoint != null)
this.Table.DeleteEntity(Endpoint.To<EndpointTableRow>(storedEndpoint));

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

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="aspnet.suppressformsredirect" version="0.0.1.4" />
<package id="HttpClient" version="0.6.0" />
<package id="JsonValue" version="0.6.0" />
<package id="WebApi" version="0.6.0" />
<package id="WebApi.All" version="0.6.0" />
<package id="WebApi.Enhancements" version="0.6.0" />
<package id="WebApi.OData" version="0.6.0" />
<package id="AspNetWebApi" version="4.0.20126.16343" />
<package id="AspNetWebApi.Core" version="4.0.20126.16343" />
<package id="System.Json" version="4.0.20126.16343" />
<package id="System.Net.Http" version="2.0.20126.16343" />
<package id="System.Net.Http.Formatting" version="4.0.20126.16343" />
<package id="System.Web.Http.Common" version="4.0.20126.16343" />
</packages>

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

@ -12,6 +12,7 @@
<AssemblyName>WindowsAzure.Storage.Proxy</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -35,51 +36,43 @@
<Reference Include="AspNet.SuppressFormsRedirect">
<HintPath>..\packages\aspnet.suppressformsredirect.0.0.1.4\lib\40\AspNet.SuppressFormsRedirect.dll</HintPath>
</Reference>
<Reference Include="EntityDataModel">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\EntityDataModel.dll</HintPath>
</Reference>
<Reference Include="Microsoft.ApplicationServer.Http">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.ApplicationServer.Http.dll</HintPath>
</Reference>
<Reference Include="Microsoft.ApplicationServer.HttpEnhancements">
<HintPath>..\packages\WebApi.Enhancements.0.6.0\lib\40-Full\Microsoft.ApplicationServer.HttpEnhancements.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Data.Spatial">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\Microsoft.Data.Spatial.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Json">
<HintPath>..\packages\JsonValue.0.6.0\lib\40\Microsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Net.Http.Formatting">
<HintPath>..\packages\HttpClient.0.6.0\lib\40\Microsoft.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Net.Http.Formatting.OData">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\Microsoft.Net.Http.Formatting.OData.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Runtime.Serialization.Internal">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.Runtime.Serialization.Internal.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Server.Common">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.Server.Common.dll</HintPath>
</Reference>
<Reference Include="Microsoft.ServiceModel.Internal">
<HintPath>..\packages\WebApi.0.6.0\lib\40-Full\Microsoft.ServiceModel.Internal.dll</HintPath>
</Reference>
<Reference Include="Microsoft.WindowsAzure.StorageClient, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Data.OData">
<HintPath>..\packages\WebApi.OData.0.6.0\lib\40-Full\System.Data.OData.dll</HintPath>
<Reference Include="System.Json, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Json.4.0.20126.16343\lib\net40\System.Json.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http">
<HintPath>..\packages\HttpClient.0.6.0\lib\40\System.Net.Http.dll</HintPath>
<Reference Include="System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Net.Http.2.0.20126.16343\lib\net40\System.Net.Http.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.Formatting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Net.Http.Formatting.4.0.20126.16343\lib\net40\System.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Net.Http.2.0.20126.16343\lib\net40\System.Net.Http.WebRequest.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.ServiceModel.Activation" />
<Reference Include="System.ServiceModel.Web" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\AspNetWebApi.Core.4.0.20126.16343\lib\net40\System.Web.Http.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http.Common, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\System.Web.Http.Common.4.0.20126.16343\lib\net40\System.Web.Http.Common.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http.WebHost, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\AspNetWebApi.4.0.20126.16343\lib\net40\System.Web.Http.WebHost.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
@ -88,24 +81,21 @@
</ItemGroup>
<ItemGroup>
<Compile Include="ConfigurationExtensions.cs" />
<Compile Include="Constants.cs" />
<Compile Include="Handlers\ContentTypeSanitizerMessageHandler.cs" />
<Compile Include="Handlers\ControllerFilteredMessageProcessingHandler.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="Helpers\CanonicalizedString.cs" />
<Compile Include="Helpers\CredentialExtensions.cs" />
<Compile Include="Helpers\BlobExtensions.cs" />
<Compile Include="Properties\Resource.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resource.resx</DependentUpon>
</Compile>
<Compile Include="QueuesProxyService.cs" />
<Compile Include="Controllers\QueuesProxyController.cs" />
<Compile Include="RouteExtensions.cs" />
<Compile Include="SasCloudBlobContainerProperties.cs" />
<Compile Include="Security\AuthorizeTablesAccessAttribute.cs" />
<Compile Include="Security\AuthorizeQueuesAccessAttribute.cs" />
<Compile Include="Security\AuthorizeBlobsAccessAttribute.cs" />
<Compile Include="Security\FuncBasedFilterAttribute.cs" />
<Compile Include="Security\FuncBasedOperationHandler.cs" />
<Compile Include="TablesProxyService.cs" />
<Compile Include="Security\FuncBasedAuthorizationFilterAttribute.cs" />
<Compile Include="Controllers\TablesProxyController.cs" />
<Compile Include="Helpers\Extensions.cs" />
<Compile Include="Handlers\AzureQueuesProxyHandler.cs" />
<Compile Include="Handlers\AzureTablesProxyHandler.cs" />
@ -114,23 +104,15 @@
<Compile Include="SasCloudBlobContainerListResponse.cs" />
<Compile Include="StorageServicesConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SharedAccessSignatureService.cs" />
<Compile Include="Controllers\SharedAccessSignatureController.cs" />
<Compile Include="StorageServicesContext.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Properties\Resource.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>$(ProjectDir)..\NuGet\NuGet.exe install $(ProjectDir)packages.config -OutputDirectory $(ProjectDir)..\packages\</PreBuildEvent>
<PreBuildEvent>$(ProjectDir)..\.nuget\NuGet.exe install $(ProjectDir)packages.config -OutputDirectory $(ProjectDir)..\packages\</PreBuildEvent>
</PropertyGroup>
<!-- 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.

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

@ -16,36 +16,17 @@
namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
{
using System;
using System.Linq;
using Microsoft.ApplicationServer.Http;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Security;
using System.Net.Http;
using System.Web.Http;
internal static class ConfigurationExtensions
{
internal static HttpConfiguration AddDelegatingHandlers(this HttpConfiguration config, params Type[] handlers)
internal static HttpConfiguration AddDelegatingHandlers(this HttpConfiguration config, params DelegatingHandler[] handlers)
{
handlers.ToList().ForEach(t => config.MessageHandlers.Add(t));
return config;
}
internal static HttpConfiguration AddRequestHandlers(this HttpConfiguration config)
{
var requestHandlers = config.RequestHandlers;
config.RequestHandlers = (c, e, od) =>
{
if (requestHandlers != null)
requestHandlers(c, e, od); // Original request handler
var filterAttribute = od.Attributes.Where(a => typeof(FuncBasedFilterAttribute).IsAssignableFrom(a.GetType())).Cast<FuncBasedFilterAttribute>().ToList();
filterAttribute.ForEach(a => c.Add(new FuncBasedOperationHandler(a)));
};
return config;
}
}
}
}

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

@ -0,0 +1,45 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
{
public class Constants
{
public const string CloudStorageAccountNullArgumentErrorMessage = "The Storage Account setting cannot be null.";
public const string CompMustBeSasArgumentErrorMessage = "Argument comp must be sas for this operation.";
public const string ConfigureActionArgumentNullErrorMessage = "Parameter configureAction cannot be null.";
public const string ContainerCannotBeNullErrorMessage = "Container can not be null.";
public const string ContainerNameNullArgumentErrorMessage = "The containerName cannot be null.";
public const string HttpClientDisposedErrorString = "The connection with Windows Azure has been closed before the result could be read.";
public const string InvalidPublicAccessModeArgumentErrorMessage = "Container Access Mode is invalid.";
public const string PublicAccessNotSpecifiedErrorMessage = "You have specified an ACL operation but not sent the required HTTP header.";
public const string RequestCannotBeNullErrorMessage = "Request can not be null.";
public const string RequestNullErrorMessage = "Called service with null HttpRequestMessage.";
public const string ResponseNullArgumentErrorString = "Response can not be null.";
public const string WindowsAzureStorageExceptionStringMessage = "There was an error when sending data to Windows Azure Storage.";
}
}

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

@ -0,0 +1,82 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
{
using System;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Handlers;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Helpers;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Security;
public class QueuesProxyController : ApiController
{
private static readonly AzureQueuesProxyHandler Proxy = new AzureQueuesProxyHandler();
[AuthorizeQueuesAccess, CLSCompliant(false)]
public HttpResponseMessage Post([FromUri]string path)
{
if (this.Request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Constants.RequestCannotBeNullErrorMessage, Constants.RequestCannotBeNullErrorMessage);
this.Request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path ?? string.Empty;
return Proxy.ProcessRequest(this.Request);
}
[AuthorizeQueuesAccess, CLSCompliant(false)]
public HttpResponseMessage Put([FromUri]string path)
{
if (this.Request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Constants.RequestCannotBeNullErrorMessage, Constants.RequestCannotBeNullErrorMessage);
this.Request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path ?? string.Empty;
return Proxy.ProcessRequest(this.Request);
}
[AuthorizeQueuesAccess, CLSCompliant(false)]
public HttpResponseMessage Get(string path)
{
if (this.Request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Constants.RequestCannotBeNullErrorMessage, Constants.RequestCannotBeNullErrorMessage);
this.Request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path ?? string.Empty;
return Proxy.ProcessRequest(this.Request);
}
[AuthorizeQueuesAccess, CLSCompliant(false)]
public HttpResponseMessage Delete(string path)
{
if (this.Request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Constants.RequestCannotBeNullErrorMessage, Constants.RequestCannotBeNullErrorMessage);
this.Request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path ?? string.Empty;
return Proxy.ProcessRequest(this.Request);
}
[AuthorizeQueuesAccess, CLSCompliant(false)]
[AcceptVerbs("HEAD")]
public HttpResponseMessage Head(string path)
{
if (this.Request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Constants.RequestCannotBeNullErrorMessage, Constants.RequestCannotBeNullErrorMessage);
this.Request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path ?? string.Empty;
return Proxy.ProcessRequest(this.Request);
}
}
}

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

@ -22,20 +22,14 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text.RegularExpressions;
using Microsoft.ApplicationServer.Http.Dispatcher;
using System.Web.Http;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Helpers;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Properties;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Security;
using Microsoft.WindowsAzure.StorageClient;
[ServiceContract]
[ServiceBehavior(IncludeExceptionDetailInFaults = false)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class SharedAccessSignatureService
public class SharedAccessSignatureController : ApiController
{
private const SharedAccessPermissions ContainerSharedAccessPermissions = SharedAccessPermissions.Write | SharedAccessPermissions.Delete | SharedAccessPermissions.List | SharedAccessPermissions.Read;
@ -45,48 +39,43 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
private readonly CloudBlobClient cloudBlobClient;
public SharedAccessSignatureService()
public SharedAccessSignatureController()
: this(StorageServicesContext.Current.Configuration.CloudStorageAccount)
{
}
public SharedAccessSignatureService(CloudStorageAccount storageAccount)
public SharedAccessSignatureController(CloudStorageAccount storageAccount)
{
if (storageAccount == null)
throw new ArgumentNullException("storageAccount", Resource.CloudStorageAccountNullArgumentErrorMessage);
throw new ArgumentNullException("storageAccount", Constants.CloudStorageAccountNullArgumentErrorMessage);
this.cloudBlobClient = storageAccount.CreateCloudBlobClient();
}
[OperationContract]
[AuthorizeBlobsAccess]
[CLSCompliant(false)]
[WebInvoke(Method = "PUT", UriTemplate = "/containers/{containerName}?comp={operation}")]
public HttpResponseMessage CreateContainer(HttpRequestMessage request, string containerName, string operation)
public HttpResponseMessage Put(string containerName, string comp)
{
if (request == null)
throw new ArgumentNullException("request", Resource.RequestNullErrorMessage);
// Determine if the public-access header was sent
string publicAccessMode = GetPublicAccessMode(request);
string publicAccessMode = GetPublicAccessMode(this.Request);
// operation is ACL but headers have not been sent
if (string.IsNullOrEmpty(publicAccessMode) && !string.IsNullOrEmpty(operation) && operation.Equals("acl", StringComparison.OrdinalIgnoreCase))
if (string.IsNullOrEmpty(publicAccessMode) && !string.IsNullOrEmpty(comp) && comp.Equals("acl", StringComparison.OrdinalIgnoreCase))
publicAccessMode = "OFF";
// operation is null and container name is null
if (string.IsNullOrWhiteSpace(containerName) && string.IsNullOrWhiteSpace(operation))
throw WebException(Resource.ContainerNameNullArgumentErrorMessage, HttpStatusCode.BadRequest);
if (string.IsNullOrWhiteSpace(containerName) && string.IsNullOrWhiteSpace(comp))
throw WebException(Constants.ContainerNameNullArgumentErrorMessage, HttpStatusCode.BadRequest);
try
{
var responseStatusCode = HttpStatusCode.InternalServerError;
var container = this.cloudBlobClient.GetContainerReference(containerName);
UpdateContainerWithMetadataFromRequest(request, container);
UpdateContainerWithMetadataFromRequest(this.Request, container);
// operation is null --> the create container mode is requested
if (string.IsNullOrEmpty(operation))
if (string.IsNullOrEmpty(comp))
{
responseStatusCode = HttpStatusCode.Created;
container.Create();
@ -103,7 +92,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
}
// operation == metadata
if (!string.IsNullOrEmpty(operation) && operation.Equals("metadata", StringComparison.OrdinalIgnoreCase))
if (!string.IsNullOrEmpty(comp) && comp.Equals("metadata", StringComparison.OrdinalIgnoreCase))
{
responseStatusCode = HttpStatusCode.OK;
container.SetMetadata();
@ -117,11 +106,9 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
}
}
[OperationContract]
[AuthorizeBlobsAccess]
[CLSCompliant(false)]
[WebInvoke(Method = "DELETE", UriTemplate = "/containers/{containerName}")]
public HttpResponseMessage DeleteContainer(string containerName)
public HttpResponseMessage Delete(string containerName)
{
try
{
@ -136,10 +123,9 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
}
}
[OperationContract]
[AuthorizeBlobsAccess]
[CLSCompliant(false)]
[WebInvoke(Method = "HEAD", UriTemplate = "/containers/{containerName}")]
[AcceptVerbs("HEAD")]
public HttpResponseMessage GetContainerProperties(string containerName)
{
try
@ -165,17 +151,23 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
}
}
[OperationContract]
[AuthorizeBlobsAccess]
[CLSCompliant(false)]
[WebGet(UriTemplate = "/containers?prefix={containerPrefix}")]
public HttpResponseMessage<SasCloudBlobContainerListResponse> ListContainers(string containerPrefix)
public HttpResponseMessage<SasCloudBlobContainerListResponse> GetContainers()
{
return this.GetContainers(string.Empty);
}
[AuthorizeBlobsAccess]
[CLSCompliant(false)]
public HttpResponseMessage<SasCloudBlobContainerListResponse> GetContainers(string prefix)
{
IEnumerable<CloudBlobContainer> containers;
if (!string.IsNullOrEmpty(containerPrefix))
if (!string.IsNullOrEmpty(prefix))
{
containerPrefix = containerPrefix.TrimStart('/', '\\').Replace('\\', '/');
containers = this.cloudBlobClient.ListContainers(containerPrefix);
prefix = prefix.TrimStart('/', '\\').Replace('\\', '/');
containers = this.cloudBlobClient.ListContainers(prefix);
}
else
{
@ -193,14 +185,12 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
return new HttpResponseMessage<SasCloudBlobContainerListResponse>(result, HttpStatusCode.OK);
}
[OperationContract]
[AuthorizeBlobsAccess]
[CLSCompliant(false)]
[WebGet(UriTemplate = "/containers/{containerName}?comp={operation}")]
public HttpResponseMessage GetContainerSharedAccessSignature(string containerName, string operation)
public HttpResponseMessage GetContainerSharedAccessSignature(string containerName, string comp)
{
if (string.IsNullOrEmpty(operation) || !operation.Equals("sas", StringComparison.OrdinalIgnoreCase))
throw WebException(Resource.CompMustBeSasArgumentErrorMessage, HttpStatusCode.BadRequest);
if (string.IsNullOrEmpty(comp) || !comp.Equals("sas", StringComparison.OrdinalIgnoreCase))
throw WebException(Constants.CompMustBeSasArgumentErrorMessage, HttpStatusCode.BadRequest);
var container = this.cloudBlobClient.GetContainerReference(containerName);
var sas = container.GetSharedAccessSignature(new SharedAccessPolicy
@ -213,14 +203,12 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
return new HttpResponseMessage { Content = new StringContent(uriBuilder.Uri.AbsoluteUri), StatusCode = HttpStatusCode.OK };
}
[OperationContract]
[AuthorizeBlobsAccess]
[CLSCompliant(false)]
[WebGet(UriTemplate = "/blobs/{containerName}/{*blobName}?comp={operation}")]
public HttpResponseMessage GetBlobSharedAccessSignature(string containerName, string blobName, string operation)
public HttpResponseMessage GetBlobSharedAccessSignature(string containerName, string blobName, string comp)
{
if (string.IsNullOrEmpty(operation) || !operation.Equals("sas", StringComparison.OrdinalIgnoreCase))
throw WebException(Resource.CompMustBeSasArgumentErrorMessage, HttpStatusCode.BadRequest);
if (string.IsNullOrEmpty(comp) || !comp.Equals("sas", StringComparison.OrdinalIgnoreCase))
throw WebException(Constants.CompMustBeSasArgumentErrorMessage, HttpStatusCode.BadRequest);
try
{
@ -314,4 +302,4 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
return publicAccessMode;
}
}
}
}

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

@ -0,0 +1,82 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
{
using System;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Handlers;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Helpers;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Security;
public class TablesProxyController : ApiController
{
private static readonly AzureTablesProxyHandler Proxy = new AzureTablesProxyHandler();
[AuthorizeTablesAccess, CLSCompliant(false)]
public HttpResponseMessage Post([FromUri]string path)
{
if (this.Request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Constants.RequestCannotBeNullErrorMessage, Constants.RequestCannotBeNullErrorMessage);
this.Request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path ?? string.Empty;
return Proxy.ProcessRequest(this.Request);
}
[AuthorizeTablesAccess, CLSCompliant(false)]
public HttpResponseMessage Put([FromUri]string path)
{
if (this.Request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Constants.RequestCannotBeNullErrorMessage, Constants.RequestCannotBeNullErrorMessage);
this.Request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path ?? string.Empty;
return Proxy.ProcessRequest(this.Request);
}
[AuthorizeTablesAccess, CLSCompliant(false)]
public HttpResponseMessage Get(string path)
{
if (this.Request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Constants.RequestCannotBeNullErrorMessage, Constants.RequestCannotBeNullErrorMessage);
this.Request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path ?? string.Empty;
return Proxy.ProcessRequest(this.Request);
}
[AuthorizeTablesAccess, CLSCompliant(false)]
public HttpResponseMessage Delete(string path)
{
if (this.Request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Constants.RequestCannotBeNullErrorMessage, Constants.RequestCannotBeNullErrorMessage);
this.Request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path ?? string.Empty;
return Proxy.ProcessRequest(this.Request);
}
[AuthorizeTablesAccess, CLSCompliant(false)]
[AcceptVerbs("MERGE")]
public HttpResponseMessage Merge([FromUri]string path)
{
if (this.Request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Constants.RequestCannotBeNullErrorMessage, Constants.RequestCannotBeNullErrorMessage);
this.Request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path ?? string.Empty;
return Proxy.ProcessRequest(this.Request);
}
}
}

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

@ -0,0 +1,36 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Handlers
{
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
public class ContentTypeSanitizerMessageHandler : ControllerFilteredMessageProcessingHandler
{
protected override HttpRequestMessage ProcessRequestHandler(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Content.Headers.ContentType == null)
{
// Set the default Content-Type when it is not specified
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
}
return request;
}
}
}

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

@ -0,0 +1,53 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Handlers
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Web.Http;
public abstract class ControllerFilteredMessageProcessingHandler : MessageProcessingHandler
{
public IList<string> ConfiguredControllers { get; set; }
protected abstract HttpRequestMessage ProcessRequestHandler(HttpRequestMessage request, CancellationToken cancellationToken);
protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken)
{
var routeData = request.GetRouteData();
var controllerName = routeData.Values.ContainsKey("controller") ?
routeData.Values["controller"].ToString() :
string.Empty;
if (this.ConfiguredControllers == null ||
this.ConfiguredControllers.Any(c => c.Equals(controllerName, StringComparison.OrdinalIgnoreCase)))
{
return this.ProcessRequestHandler(request, cancellationToken);
}
return request;
}
protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken)
{
return response;
}
}
}

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

@ -26,7 +26,6 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Handlers
using System.Web;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Helpers;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Properties;
public abstract class StorageProxyHandler
{
@ -47,7 +46,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Handlers
public HttpResponseMessage ProcessRequest(HttpRequestMessage request)
{
if (request == null)
throw new ArgumentNullException("request", Resource.RequestCannotBeNullErrorMessage);
throw new ArgumentNullException("request", Constants.RequestCannotBeNullErrorMessage);
var originalUri = request.RequestUri;
@ -79,7 +78,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Handlers
protected string GetAzureStorageRequestBody(string proxyRequestBody, HttpRequestMessage request)
{
if (request == null)
throw new ArgumentNullException("request", Resource.RequestCannotBeNullErrorMessage);
throw new ArgumentNullException("request", Constants.RequestCannotBeNullErrorMessage);
if (string.IsNullOrWhiteSpace(proxyRequestBody))
{
@ -111,7 +110,6 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Handlers
return azureStorageResponseBody.Replace(oldValue, newValue);
}
[CLSCompliant(false)]
protected abstract void SignRequest(HttpRequestMessage request);
private static string GetLocalPath(Uri originalUri, Uri mappedUri, HttpRequestMessage request)
@ -167,18 +165,18 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Handlers
{
var task = azureClient.SendAsync(request);
// Synchronize Azure Invokation
// Synchronize Azure Invocation
task.Wait();
return task.Result;
}
catch (HttpException webException)
{
throw Extensions.StorageException(HttpStatusCode.InternalServerError, Resource.WindowsAzureStorageExceptionStringMessage, webException.Message);
throw Extensions.StorageException(HttpStatusCode.InternalServerError, Constants.WindowsAzureStorageExceptionStringMessage, webException.Message);
}
catch (ObjectDisposedException exception)
{
throw Extensions.StorageException(HttpStatusCode.InternalServerError, Resource.HttpClientDisposedErrorString, exception.Message);
throw Extensions.StorageException(HttpStatusCode.InternalServerError, Constants.HttpClientDisposedErrorString, exception.Message);
}
}
}

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

@ -17,15 +17,14 @@
namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Helpers
{
using System;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Properties;
public static class BlobExtensions
{
public static SasCloudBlobContainer ToModel(this StorageClient.CloudBlobContainer container)
public static SasCloudBlobContainer ToModel(this Microsoft.WindowsAzure.StorageClient.CloudBlobContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container", Resource.ContainerCannotBeNullErrorMessage);
throw new ArgumentNullException("container", Constants.ContainerCannotBeNullErrorMessage);
}
return new SasCloudBlobContainer

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

@ -26,6 +26,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Helpers
using System.Net.Http.Headers;
using System.Text;
using System.Web;
using Microsoft.WindowsAzure;
internal static class CredentialExtensions
{
@ -74,7 +75,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Helpers
canonicalizedString.AppendCanonicalizedElement("0");
else
{
canonicalizedString.AppendCanonicalizedElement(string.Empty);
canonicalizedString.AppendCanonicalizedElement(string.Empty);
}
canonicalizedString.AppendCanonicalizedElement(string.Empty);
@ -179,7 +180,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Helpers
{
var canonicalizedString = new CanonicalizedString(string.Empty);
var keyList =
var keyList =
headers.Where(h => h.Key.StartsWith("x-ms-", StringComparison.OrdinalIgnoreCase)).Select(header => header.Key).ToList();
keyList.Sort();

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

@ -21,7 +21,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Helpers
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using Microsoft.ApplicationServer.Http.Dispatcher;
using System.Web.Http;
public static class Extensions
{
@ -54,7 +54,8 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Helpers
response.ReasonPhrase = error;
response.Content = new StringContent(errorMessage);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/atom+xml");
return new HttpResponseException(response);
}
}
}
}

187
CloudServices.Storage/Properties/Resource.Designer.cs сгенерированный
Просмотреть файл

@ -1,187 +0,0 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.235
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.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 Resource {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resource() {
}
/// <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.WindowsAzure.Samples.CloudServices.Storage.Properties.Resource", typeof(Resource).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 Storage Account setting cannot be null.
/// </summary>
internal static string CloudStorageAccountNullArgumentErrorMessage {
get {
return ResourceManager.GetString("CloudStorageAccountNullArgumentErrorMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Argument comp must be sas for this operation.
/// </summary>
internal static string CompMustBeSasArgumentErrorMessage {
get {
return ResourceManager.GetString("CompMustBeSasArgumentErrorMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Parameter configureAction cannot be null.
/// </summary>
internal static string ConfigureActionArgumentNullErrorMessage {
get {
return ResourceManager.GetString("ConfigureActionArgumentNullErrorMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Container can not be null..
/// </summary>
internal static string ContainerCannotBeNullErrorMessage {
get {
return ResourceManager.GetString("ContainerCannotBeNullErrorMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The containerName cannot be null..
/// </summary>
internal static string ContainerNameNullArgumentErrorMessage {
get {
return ResourceManager.GetString("ContainerNameNullArgumentErrorMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The connection with Windows Azure has been closed before the result could be read.
/// </summary>
internal static string HttpClientDisposedErrorString {
get {
return ResourceManager.GetString("HttpClientDisposedErrorString", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Container Access Mode is invalid.
/// </summary>
internal static string InvalidPublicAccessModeArgumentErrorMessage {
get {
return ResourceManager.GetString("InvalidPublicAccessModeArgumentErrorMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to You have specified an ACL operation but not sent the required HTTP header.
/// </summary>
internal static string PublicAccessNotSpecifiedErrorMessage {
get {
return ResourceManager.GetString("PublicAccessNotSpecifiedErrorMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Request can not be null..
/// </summary>
internal static string RequestCannotBeNullErrorMessage {
get {
return ResourceManager.GetString("RequestCannotBeNullErrorMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Called service with null HttpRequestMessage.
/// </summary>
internal static string RequestNullErrorMessage {
get {
return ResourceManager.GetString("RequestNullErrorMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Response can not be null..
/// </summary>
internal static string ResponseNullArgumentErrorString {
get {
return ResourceManager.GetString("ResponseNullArgumentErrorString", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to There was an error when sending data to Windows Azure Storage.
/// </summary>
internal static string WindowsAzureStorageExceptionStringMessage {
get {
return ResourceManager.GetString("WindowsAzureStorageExceptionStringMessage", resourceCulture);
}
}
}
}

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

@ -1,156 +0,0 @@
<?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="CloudStorageAccountNullArgumentErrorMessage" xml:space="preserve">
<value>The Storage Account setting cannot be null</value>
</data>
<data name="ContainerNameNullArgumentErrorMessage" xml:space="preserve">
<value>The containerName cannot be null.</value>
</data>
<data name="CompMustBeSasArgumentErrorMessage" xml:space="preserve">
<value>Argument comp must be sas for this operation</value>
</data>
<data name="PublicAccessNotSpecifiedErrorMessage" xml:space="preserve">
<value>You have specified an ACL operation but not sent the required HTTP header</value>
</data>
<data name="RequestNullErrorMessage" xml:space="preserve">
<value>Called service with null HttpRequestMessage</value>
</data>
<data name="InvalidPublicAccessModeArgumentErrorMessage" xml:space="preserve">
<value>Container Access Mode is invalid</value>
</data>
<data name="ConfigureActionArgumentNullErrorMessage" xml:space="preserve">
<value>Parameter configureAction cannot be null</value>
</data>
<data name="RequestCannotBeNullErrorMessage" xml:space="preserve">
<value>Request can not be null.</value>
</data>
<data name="ResponseNullArgumentErrorString" xml:space="preserve">
<value>Response can not be null.</value>
</data>
<data name="ContainerCannotBeNullErrorMessage" xml:space="preserve">
<value>Container can not be null.</value>
</data>
<data name="WindowsAzureStorageExceptionStringMessage" xml:space="preserve">
<value>There was an error when sending data to Windows Azure Storage</value>
</data>
<data name="HttpClientDisposedErrorString" xml:space="preserve">
<value>The connection with Windows Azure has been closed before the result could be read</value>
</data>
</root>

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

@ -1,87 +0,0 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
{
using System;
using System.Net;
using System.Net.Http;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Handlers;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Helpers;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Properties;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Security;
[ServiceContract]
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class QueuesProxyService
{
private static readonly AzureQueuesProxyHandler Proxy = new AzureQueuesProxyHandler();
[WebInvoke(Method = "POST", UriTemplate = "{*path}"), OperationContract, AuthorizeQueuesAccess, CLSCompliant(false)]
public HttpResponseMessage HandlePost(HttpRequestMessage request, string path)
{
if (request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Resource.RequestCannotBeNullErrorMessage, Resource.RequestCannotBeNullErrorMessage);
request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path;
return Proxy.ProcessRequest(request);
}
[WebInvoke(Method = "PUT", UriTemplate = "{*path}"), OperationContract, AuthorizeQueuesAccess, CLSCompliant(false)]
public HttpResponseMessage HandlePut(HttpRequestMessage request, string path)
{
if (request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Resource.RequestCannotBeNullErrorMessage, Resource.RequestCannotBeNullErrorMessage);
request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path;
return Proxy.ProcessRequest(request);
}
[WebInvoke(Method = "GET", UriTemplate = "{*path}"), OperationContract, AuthorizeQueuesAccess, CLSCompliant(false)]
public HttpResponseMessage HandleGet(HttpRequestMessage request, string path)
{
if (request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Resource.RequestCannotBeNullErrorMessage, Resource.RequestCannotBeNullErrorMessage);
request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path;
return Proxy.ProcessRequest(request);
}
[WebInvoke(Method = "DELETE", UriTemplate = "{*path}"), OperationContract, AuthorizeQueuesAccess, CLSCompliant(false)]
public HttpResponseMessage HandleDelete(HttpRequestMessage request, string path)
{
if (request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Resource.RequestCannotBeNullErrorMessage, Resource.RequestCannotBeNullErrorMessage);
request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path;
return Proxy.ProcessRequest(request);
}
[WebInvoke(Method = "HEAD", UriTemplate = "{*path}"), OperationContract, AuthorizeQueuesAccess, CLSCompliant(false)]
public HttpResponseMessage HandleMerge(HttpRequestMessage request, string path)
{
if (request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Resource.RequestCannotBeNullErrorMessage, Resource.RequestCannotBeNullErrorMessage);
request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path;
return Proxy.ProcessRequest(request);
}
}
}

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

@ -16,53 +16,87 @@
namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
{
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web.Http;
using System.Web.Routing;
using Microsoft.ApplicationServer.Http;
public static class RouteExtensions
{
public static void MapQueuesProxyServiceRoute(this RouteCollection routes, string prefix)
{
var handlers = StorageServicesContext.Current.Configuration.DelegatingHandlers.ToArray();
routes.MapQueuesProxyServiceRoute(prefix, handlers);
routes.MapQueuesProxyServiceRoute(prefix, new DelegatingHandler[] { });
}
public static void MapQueuesProxyServiceRoute(this RouteCollection routes, string prefix, params Type[] handlers)
public static void MapQueuesProxyServiceRoute(this RouteCollection routes, string prefix, params DelegatingHandler[] handlers)
{
var configuration = new HttpConfiguration().AddDelegatingHandlers(handlers).AddRequestHandlers();
var currentConfiguration = GlobalConfiguration.Configuration;
routes.MapServiceRoute<QueuesProxyService>(prefix, configuration);
// Handlers
currentConfiguration.AddDelegatingHandlers(handlers)
.AddDelegatingHandlers(
new[]
{
new Handlers.ContentTypeSanitizerMessageHandler { ConfiguredControllers = new[] { "QueuesProxy" } }
});
// Routes
routes.MapHttpRoute(
name: prefix,
routeTemplate: prefix + "/{*path}",
defaults: new { Controller = "QueuesProxy", path = RouteParameter.Optional });
}
public static void MapTablesProxyServiceRoute(this RouteCollection routes, string prefix)
{
var handlers = StorageServicesContext.Current.Configuration.DelegatingHandlers.ToArray();
routes.MapTablesProxyServiceRoute(prefix, handlers);
routes.MapTablesProxyServiceRoute(prefix, new DelegatingHandler[] { });
}
public static void MapTablesProxyServiceRoute(this RouteCollection routes, string prefix, params Type[] handlers)
public static void MapTablesProxyServiceRoute(this RouteCollection routes, string prefix, params DelegatingHandler[] handlers)
{
var configuration = new HttpConfiguration().AddDelegatingHandlers(handlers).AddRequestHandlers();
var currentConfiguration = GlobalConfiguration.Configuration;
routes.MapServiceRoute<TablesProxyService>(prefix, configuration);
// Formatters
currentConfiguration.Formatters.XmlFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/atom+xml"));
// Handlers
currentConfiguration.AddDelegatingHandlers(handlers);
// Routes
routes.MapHttpRoute(
name: prefix,
routeTemplate: prefix + "/{*path}",
defaults: new { Controller = "TablesProxy", path = RouteParameter.Optional });
}
public static void MapSasServiceRoute(this RouteCollection routes, string prefix)
{
var handlers = StorageServicesContext.Current.Configuration.DelegatingHandlers.ToArray();
routes.MapSasServiceRoute(prefix, handlers);
routes.MapSasServiceRoute(prefix, new DelegatingHandler[] { });
}
public static void MapSasServiceRoute(this RouteCollection routes, string prefix, params Type[] handlers)
public static void MapSasServiceRoute(this RouteCollection routes, string prefix, params DelegatingHandler[] handlers)
{
var configuration = new HttpConfiguration().AddDelegatingHandlers(handlers).AddRequestHandlers();
var currentConfiguration = GlobalConfiguration.Configuration;
routes.MapServiceRoute<SharedAccessSignatureService>(prefix, configuration);
// Handlers
currentConfiguration.AddDelegatingHandlers(handlers);
// Routes
routes.MapHttpRoute(
name: prefix + "_Containers",
routeTemplate: prefix + "/containers",
defaults: new { Controller = "SharedAccessSignature" });
routes.MapHttpRoute(
name: prefix + "_Container",
routeTemplate: prefix + "/containers/{containerName}",
defaults: new { Controller = "SharedAccessSignature", containerName = RouteParameter.Optional });
routes.MapHttpRoute(
name: prefix + "_Blob",
routeTemplate: prefix + "/blobs/{containerName}/{*blobName}",
defaults: new { Controller = "SharedAccessSignature" });
}
}
}
}

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

@ -18,13 +18,14 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Security
{
using System;
using System.Net.Http;
using System.Web.Http.Controllers;
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
internal sealed class AuthorizeBlobsAccessAttribute : FuncBasedFilterAttribute
internal sealed class AuthorizeBlobsAccessAttribute : FuncBasedAuthorizationFilterAttribute
{
public override Func<HttpRequestMessage, bool> Filter
public override Func<HttpActionContext, bool> Filter
{
get { return StorageServicesContext.Current.Configuration.AuthorizeBlobsAccess; }
}
}
}
}

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

@ -18,13 +18,14 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Security
{
using System;
using System.Net.Http;
using System.Web.Http.Controllers;
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
internal sealed class AuthorizeQueuesAccessAttribute : FuncBasedFilterAttribute
internal sealed class AuthorizeQueuesAccessAttribute : FuncBasedAuthorizationFilterAttribute
{
public override Func<HttpRequestMessage, bool> Filter
public override Func<HttpActionContext, bool> Filter
{
get { return StorageServicesContext.Current.Configuration.AuthorizeQueuesAccess; }
}
}
}
}

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

@ -18,13 +18,14 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Security
{
using System;
using System.Net.Http;
using System.Web.Http.Controllers;
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
internal sealed class AuthorizeTablesAccessAttribute : FuncBasedFilterAttribute
internal sealed class AuthorizeTablesAccessAttribute : FuncBasedAuthorizationFilterAttribute
{
public override Func<HttpRequestMessage, bool> Filter
public override Func<HttpActionContext, bool> Filter
{
get { return StorageServicesContext.Current.Configuration.AuthorizeTablesAccess; }
}
}
}
}

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

@ -0,0 +1,50 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Security
{
using System;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
internal abstract class FuncBasedAuthorizationFilterAttribute : AuthorizationFilterAttribute
{
public abstract Func<HttpActionContext, bool> Filter { get; }
public override void OnAuthorization(HttpActionContext actionContext)
{
if (this.Filter(actionContext))
{
base.OnAuthorization(actionContext);
}
else
{
// HACK: Prevent ASP.NET Forms Authentication to redirect the user to the login page.
// This thread-safe approach adds a header with the suppression to be read on the
// OnEndRequest event of the pipelien. In order to fully support the supression you should have the ASP.NET Module
// that does this (SuppressFormsAuthenticationRedirectModule).
var response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.Headers.Add(SuppressFormsAuthenticationRedirectModule.SuppressFormsHeaderName, "true");
throw new HttpResponseException(response);
}
}
}
}

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

@ -1,48 +0,0 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage.Security
{
using System.Net.Http;
using System.Web;
using Microsoft.ApplicationServer.Http.Dispatcher;
internal class FuncBasedOperationHandler : HttpOperationHandler<HttpRequestMessage, HttpRequestMessage>
{
private readonly FuncBasedFilterAttribute filterAttribute;
public FuncBasedOperationHandler(FuncBasedFilterAttribute filterAttribute)
: base("response")
{
this.filterAttribute = filterAttribute;
}
protected override HttpRequestMessage OnHandle(HttpRequestMessage input)
{
if (this.filterAttribute.Filter(input))
return input;
// HACK: Prevent ASP.NET Forms Authentication to redirect the user to the login page.
// This thread-safe approach adds a header with the suppression to be read on the
// OnEndRequest event of the pipelien. In order to fully support the supression you should have the ASP.NET Module
// that does this (SuppressFormsAuthenticationRedirectModule).
var response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
response.Headers.Add(SuppressFormsAuthenticationRedirectModule.SuppressFormsHeaderName, "true");
throw new HttpResponseException(response);
}
}
}

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

@ -1,271 +0,0 @@
<StyleCopSettings Version="105">
<GlobalSettings>
<StringProperty Name="MergeSettingsFiles">NoMerge</StringProperty>
</GlobalSettings>
<Parsers>
<Parser ParserId="StyleCop.CSharp.CsParser">
<ParserSettings>
<BooleanProperty Name="AnalyzeDesignerFiles">False</BooleanProperty>
<CollectionProperty Name="GeneratedFileFilters">
<Value>\.g\.cs$</Value>
<Value>\.generated\.cs$</Value>
<Value>\.g\.i\.cs$</Value>
</CollectionProperty>
</ParserSettings>
</Parser>
</Parsers>
<Analyzers>
<Analyzer AnalyzerId="StyleCop.CSharp.NamingRules">
<AnalyzerSettings>
<CollectionProperty Name="Hungarian">
<Value>as</Value>
<Value>do</Value>
<Value>id</Value>
<Value>if</Value>
<Value>in</Value>
<Value>is</Value>
<Value>my</Value>
<Value>no</Value>
<Value>on</Value>
<Value>to</Value>
<Value>ui</Value>
</CollectionProperty>
</AnalyzerSettings>
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
<Rules>
<Rule Name="ElementsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="EnumerationItemsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationMustContainValidXml">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustHaveSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementDocumentationMustHaveSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustHaveSummaryText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementDocumentationMustHaveSummaryText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustNotHaveDefaultSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParametersMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustMatchElementParameters">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustDeclareParameterName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementReturnValueMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementReturnValueDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="VoidReturnValueMustNotBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParametersMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParametersMustBeDocumentedPartialClass">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustMatchTypeParameters">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustDeclareParameterName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PropertySummaryDocumentationMustMatchAccessors">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PropertySummaryDocumentationMustOmitSetAccessorWithRestrictedAccess">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustNotBeCopiedAndPasted">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SingleLineCommentsMustNotUseDocumentationStyleSlashes">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustNotBeEmpty">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustContainWhitespace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationMustMeetCharacterPercentage">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustMeetMinimumCharacterLength">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ConstructorSummaryDocumentationMustBeginWithStandardText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DestructorSummaryDocumentationMustBeginWithStandardText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationHeadersMustNotContainBlankLines">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="IncludedDocumentationXPathDoesNotExist">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="IncludeNodeDoesNotContainValidFileAndPath">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileMustHaveHeader">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustShowCopyright">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustHaveCopyrightText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustContainFileName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderFileNameDocumentationMustMatchFileName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustHaveValidCompanyText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.LayoutRules">
<Rules>
<Rule Name="CurlyBracketsForMultiLineStatementsMustNotShareLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="StatementMustNotBeOnSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementMustNotBeOnSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="CurlyBracketsMustNotBeOmitted">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="AllAccessorsMustBeMultiLineOrSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
</Analyzers>
</StyleCopSettings>

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

@ -18,18 +18,23 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Controllers;
using Microsoft.WindowsAzure;
public class StorageServicesConfig
{
private const int DefaultMaximmumResponseSize = 1024 * 1024;
private const int DefaultSasExpirationSize = 15;
private Func<HttpRequestMessage, bool> authorizeQueuesAccess;
private Func<HttpRequestMessage, bool> authorizeTablesAccess;
private Func<HttpRequestMessage, bool> authorizeBlobsAccess;
private Func<HttpRequestMessage, bool> authenticateRequest;
private Func<HttpActionContext, bool> authorizeQueuesAccess;
private Func<HttpActionContext, bool> authorizeTablesAccess;
private Func<HttpActionContext, bool> authorizeBlobsAccess;
private Func<HttpActionContext, bool> authenticateRequest;
private Func<HttpRequestMessage, string> mapUserName;
private IEnumerable<DelegatingHandler> delegatingHandlers;
private int containerSasExpirationTime;
private int blobsSasExpirationTime;
@ -37,7 +42,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
public StorageServicesConfig()
{
this.DelegatingHandlers = new Type[] { };
this.delegatingHandlers = new DelegatingHandler[] { };
}
public CloudStorageAccount CloudStorageAccount { get; set; }
@ -90,7 +95,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
}
}
public Func<HttpRequestMessage, bool> AuthorizeTablesAccess
public Func<HttpActionContext, bool> AuthorizeTablesAccess
{
get
{
@ -100,7 +105,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
set { this.authorizeTablesAccess = value; }
}
public Func<HttpRequestMessage, bool> AuthorizeQueuesAccess
public Func<HttpActionContext, bool> AuthorizeQueuesAccess
{
get
{
@ -110,7 +115,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
set { this.authorizeQueuesAccess = value; }
}
public Func<HttpRequestMessage, bool> AuthorizeBlobsAccess
public Func<HttpActionContext, bool> AuthorizeBlobsAccess
{
get
{
@ -120,7 +125,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
set { this.authorizeBlobsAccess = value; }
}
public Func<HttpRequestMessage, bool> AuthenticateRequest
public Func<HttpActionContext, bool> AuthenticateRequest
{
get
{
@ -146,9 +151,21 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
set { this.mapUserName = value; }
}
public IEnumerable<Type> DelegatingHandlers { get; set; }
public IEnumerable<DelegatingHandler> DelegatingHandlers
{
get
{
return this.delegatingHandlers;
}
private static bool DefaultAnonymousAccess(HttpRequestMessage message)
set
{
this.delegatingHandlers = value;
GlobalConfiguration.Configuration.AddDelegatingHandlers(value.ToArray());
}
}
private static bool DefaultAnonymousAccess(HttpActionContext message)
{
// By default, return always true (anonymous user)
return true;
@ -160,4 +177,4 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
return string.Empty;
}
}
}
}

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

@ -18,8 +18,6 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
{
using System;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Properties;
public class StorageServicesContext
{
private static readonly StorageServicesContext Instance = new StorageServicesContext();
@ -39,7 +37,7 @@ namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
public void Configure(Action<StorageServicesConfig> configureAction)
{
if (configureAction == null)
throw new ArgumentException(Resource.ConfigureActionArgumentNullErrorMessage, "configureAction");
throw new ArgumentException(Constants.ConfigureActionArgumentNullErrorMessage, "configureAction");
configureAction(this.config);
}

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

@ -1,87 +0,0 @@
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace Microsoft.WindowsAzure.Samples.CloudServices.Storage
{
using System;
using System.Net;
using System.Net.Http;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Handlers;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Helpers;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Properties;
using Microsoft.WindowsAzure.Samples.CloudServices.Storage.Security;
[ServiceContract]
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class TablesProxyService
{
private static readonly AzureTablesProxyHandler Proxy = new AzureTablesProxyHandler();
[WebInvoke(Method = "POST", UriTemplate = "{*path}"), OperationContract, AuthorizeTablesAccess, CLSCompliant(false)]
public HttpResponseMessage HandlePost(HttpRequestMessage request, string path)
{
if (request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Resource.RequestCannotBeNullErrorMessage, Resource.RequestCannotBeNullErrorMessage);
request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path;
return Proxy.ProcessRequest(request);
}
[WebInvoke(Method = "PUT", UriTemplate = "{*path}"), OperationContract, AuthorizeTablesAccess, CLSCompliant(false)]
public HttpResponseMessage HandlePut(HttpRequestMessage request, string path)
{
if (request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Resource.RequestCannotBeNullErrorMessage, Resource.RequestCannotBeNullErrorMessage);
request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path;
return Proxy.ProcessRequest(request);
}
[WebInvoke(Method = "GET", UriTemplate = "{*path}"), OperationContract, AuthorizeTablesAccess, CLSCompliant(false)]
public HttpResponseMessage HandleGet(HttpRequestMessage request, string path)
{
if (request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Resource.RequestCannotBeNullErrorMessage, Resource.RequestCannotBeNullErrorMessage);
request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path;
return Proxy.ProcessRequest(request);
}
[WebInvoke(Method = "DELETE", UriTemplate = "{*path}"), OperationContract, AuthorizeTablesAccess, CLSCompliant(false)]
public HttpResponseMessage HandleDelete(HttpRequestMessage request, string path)
{
if (request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Resource.RequestCannotBeNullErrorMessage, Resource.RequestCannotBeNullErrorMessage);
request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path;
return Proxy.ProcessRequest(request);
}
[WebInvoke(Method = "MERGE", UriTemplate = "{*path}"), OperationContract, AuthorizeTablesAccess, CLSCompliant(false)]
public HttpResponseMessage HandleMerge(HttpRequestMessage request, string path)
{
if (request == null)
throw Extensions.StorageException(HttpStatusCode.BadRequest, Resource.RequestCannotBeNullErrorMessage, Resource.RequestCannotBeNullErrorMessage);
request.Properties[StorageProxyHandler.RequestedPathPropertyName] = path;
return Proxy.ProcessRequest(request);
}
}
}

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

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="aspnet.suppressformsredirect" version="0.0.1.4" />
<package id="HttpClient" version="0.6.0" />
<package id="JsonValue" version="0.6.0" />
<package id="WebApi" version="0.6.0" />
<package id="WebApi.All" version="0.6.0" />
<package id="WebApi.Enhancements" version="0.6.0" />
<package id="WebApi.OData" version="0.6.0" />
<package id="AspNetWebApi" version="4.0.20126.16343" />
<package id="AspNetWebApi.Core" version="4.0.20126.16343" />
<package id="System.Json" version="4.0.20126.16343" />
<package id="System.Net.Http" version="2.0.20126.16343" />
<package id="System.Net.Http.Formatting" version="4.0.20126.16343" />
<package id="System.Web.Http.Common" version="4.0.20126.16343" />
</packages>

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

@ -12,6 +12,8 @@
<AssemblyName>Common</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -81,6 +83,7 @@
<Compile Include="Storage\ITableServiceEntity.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.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">

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

@ -45,23 +45,23 @@ namespace Microsoft.WindowsAzure.Samples.Common.JobEngine.Conditions
this.timer.Start();
}
public void Dispose()
{
timer.Dispose();
signal.Dispose();
}
public Func<bool> TickFunc
{
get
{
return () =>
{
this.signal.WaitOne();
return true;
};
{
this.signal.WaitOne();
return true;
};
}
}
public void Dispose()
{
this.timer.Dispose();
this.signal.Dispose();
}
}
}
}

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

@ -30,5 +30,5 @@ namespace Microsoft.WindowsAzure.Samples.Common.JobEngine.Language
{
return new TaskBuilder<T>(condition);
}
}
}
}

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

@ -72,12 +72,12 @@ namespace Microsoft.WindowsAzure.Samples.Common.JobEngine.Language
public void Start(ExecutionModel execution)
{
ThreadPool.QueueUserWorkItem(s =>
{
while (true)
{
while (true)
{
Cycle();
}
});
Cycle();
}
});
}
public void Start()

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

@ -35,7 +35,7 @@ namespace Microsoft.WindowsAzure.Samples.Common.Storage
public AzureBlobContainer(CloudStorageAccount account, string containerName)
: this(account, containerName.ToLowerInvariant(), false)
{
{
}
public AzureBlobContainer(CloudStorageAccount account, string containerName, bool jsonpSupport)
@ -74,7 +74,7 @@ namespace Microsoft.WindowsAzure.Samples.Common.Storage
{
permissions.PublicAccess = BlobContainerPublicAccessType.Container;
}
this.container.SetPermissions(permissions);
}

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

@ -43,7 +43,7 @@ namespace Microsoft.WindowsAzure.Samples.Common.Storage
entity.RowKey = Guid.NewGuid().ToString();
Array.ForEach(
entity.GetType().GetProperties(
BindingFlags.Public | BindingFlags.Instance),
BindingFlags.Public | BindingFlags.Instance),
p =>
{
if ((p.Name != "PartitionKey") && (p.Name != "RowKey") && (p.Name != "Timestamp"))

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

@ -48,7 +48,7 @@ namespace Microsoft.WindowsAzure.Samples.Common.Storage
blob.UploadText("text", "text");
blob.ReleaseLease(leaseId);
}
public static string AcquireLease(this CloudBlob blob)
{
var creds = blob.ServiceClient.Credentials;

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

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

@ -27,6 +27,8 @@
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\Source\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -115,6 +117,7 @@
</CodeAnalysisDictionary>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\nuget.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">

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

@ -1,69 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License.
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License.
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution.
You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
2. You must cause any modified files to carry prominent notices stating that You changed the files; and
3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions.
Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks.
This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty.
Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability.
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability.
While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.

Двоичные данные
NuGet/NuGet.exe

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

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

@ -1 +0,0 @@

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

@ -1 +0,0 @@

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

@ -22,6 +22,10 @@ namespace Microsoft.WindowsAzure.Samples.Phone.Notifications
public string ApplicationId { get; set; }
public string DeviceId { get; set; }
public string ClientId { get; set; }
public string DeviceType { get; set; }
public string TileId { get; set; }
}
}
}

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

@ -20,8 +20,8 @@ namespace Microsoft.WindowsAzure.Samples.Phone.Notifications
public interface IPushClient
{
void Connect(Action<PushRegistrationResponse> callback);
void Register(Action<PushRegistrationResponse> callback, Uri tileNavigationUri = null);
void Disconnect(Action<PushRegistrationResponse> callback);
void Unregister(Action<PushRegistrationResponse> callback, Uri tileNavigationUri = null);
}
}
}

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

@ -17,6 +17,7 @@
namespace Microsoft.WindowsAzure.Samples.Phone.Notifications
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
@ -31,14 +32,13 @@ namespace Microsoft.WindowsAzure.Samples.Phone.Notifications
private readonly Action<WebRequest> signRequestDelegate;
private readonly Dispatcher dispatcher;
private readonly string applicationId;
private readonly string deviceId;
private readonly string clientId;
private readonly string deviceType;
private readonly IList<Uri> notificationEndpoints = new List<Uri>();
private static Uri primaryTileEnpointIdentifier = new Uri("/", UriKind.Relative);
private string channelUri;
public PushClient(Uri endpointsServiceUri, Action<WebRequest> signRequestDelegate, string applicationId, string deviceId)
: this(endpointsServiceUri, signRequestDelegate, applicationId, deviceId, null)
{
}
public PushClient(Uri endpointsServiceUri, Action<WebRequest> signRequestDelegate, string applicationId, string deviceId, Dispatcher dispatcher)
public PushClient(Uri endpointsServiceUri, Action<WebRequest> signRequestDelegate, string applicationId, string clientId, string deviceType, Dispatcher dispatcher = null)
{
if (endpointsServiceUri == null)
throw new ArgumentNullException("endpointsServiceUri");
@ -49,48 +49,56 @@ namespace Microsoft.WindowsAzure.Samples.Phone.Notifications
if (string.IsNullOrWhiteSpace(applicationId))
throw new ArgumentNullException("applicationId");
if (string.IsNullOrWhiteSpace(deviceId))
throw new ArgumentNullException("deviceId");
if (string.IsNullOrWhiteSpace(clientId))
throw new ArgumentNullException("clientId");
if (string.IsNullOrWhiteSpace(deviceType))
throw new ArgumentNullException("deviceType");
this.endpointsServiceUri = endpointsServiceUri;
this.signRequestDelegate = signRequestDelegate;
this.applicationId = applicationId;
this.deviceId = deviceId;
this.clientId = clientId;
this.deviceType = deviceType;
this.dispatcher = dispatcher;
}
public void Connect(Action<PushRegistrationResponse> callback)
public void Register(Action<PushRegistrationResponse> callback, Uri tileNavigationUri = null)
{
EventHandler<PushContextErrorEventArgs> errorHandler = null;
errorHandler =
(s, e) =>
{
PushContext.Current.Error -= errorHandler;
this.DispatchCallback(callback, new PushRegistrationResponse(false, e.Exception.Message));
};
PushContext.Current.Error += errorHandler;
PushContext.Current.Connect(
c =>
{
PushContext.Current.Error -= errorHandler;
var endpoint = new Endpoint
if (string.IsNullOrWhiteSpace(this.channelUri))
{
EventHandler<PushContextErrorEventArgs> errorHandler = null;
errorHandler =
(s, e) =>
{
ApplicationId = this.applicationId,
DeviceId = this.deviceId,
ChannelUri = c.ChannelUri.ToString()
PushContext.Current.Error -= errorHandler;
this.DispatchCallback(callback, new PushRegistrationResponse(false, e.Exception.Message));
};
this.PutEndpoint(endpoint, callback);
});
PushContext.Current.Error += errorHandler;
PushContext.Current.Connect(
c =>
{
PushContext.Current.Error -= errorHandler;
this.channelUri = c.ChannelUri.AbsoluteUri;
this.PutEndpoint(tileNavigationUri, callback);
});
}
else
{
this.PutEndpoint(tileNavigationUri, callback);
}
}
public void Disconnect(Action<PushRegistrationResponse> callback)
public void Unregister(Action<PushRegistrationResponse> callback, Uri tileNavigationUri = null)
{
this.DeleteEndpoint(callback);
this.DeleteEndpoint(callback, tileNavigationUri);
PushContext.Current.Disconnect();
if (this.notificationEndpoints.Count == 0)
{
PushContext.Current.Disconnect();
}
}
protected virtual void DispatchCallback(Action<PushRegistrationResponse> callback, PushRegistrationResponse response)
@ -109,8 +117,23 @@ namespace Microsoft.WindowsAzure.Samples.Phone.Notifications
return (HttpWebRequest)WebRequestCreator.ClientHttp.Create(requestUri);
}
private void PutEndpoint(Endpoint endpoint, Action<PushRegistrationResponse> callback)
private void PutEndpoint(Uri tileNavigationUri, Action<PushRegistrationResponse> callback)
{
var endpointIdentifier = tileNavigationUri ?? primaryTileEnpointIdentifier;
if (this.notificationEndpoints.Contains(endpointIdentifier)) throw new InvalidOperationException("Navigation Uri already registered.");
var endpoint = new Endpoint
{
ApplicationId = this.applicationId,
ClientId = this.clientId,
DeviceType = this.deviceType,
ChannelUri = this.channelUri,
TileId = tileNavigationUri != null ?
tileNavigationUri.ToString() :
string.Empty
};
var request = this.ResolveRequest(this.endpointsServiceUri);
request.Method = "PUT";
request.ContentType = "application/json";
@ -145,10 +168,11 @@ namespace Microsoft.WindowsAzure.Samples.Phone.Notifications
if ((response != null) && (response.StatusCode == HttpStatusCode.Accepted))
{
this.DispatchCallback(callback, new PushRegistrationResponse(true, string.Empty));
this.notificationEndpoints.Add(endpointIdentifier);
}
else
{
this.DispatchCallback(callback, new PushRegistrationResponse(false, "The push notification channel coud not be registered in the Endpoints service."));
this.DispatchCallback(callback, new PushRegistrationResponse(false, "The specified endpoint could not be registered in the Endpoints service."));
}
}
catch (WebException webException)
@ -170,10 +194,26 @@ namespace Microsoft.WindowsAzure.Samples.Phone.Notifications
}
}
private void DeleteEndpoint(Action<PushRegistrationResponse> callback)
private void DeleteEndpoint(Action<PushRegistrationResponse> callback, Uri tileNavigationUri)
{
var endpointIdentifier = tileNavigationUri ?? primaryTileEnpointIdentifier;
if (!this.notificationEndpoints.Contains(endpointIdentifier)) throw new InvalidOperationException("Navigation Uri is not registered. Call register method first.");
var builder = new UriBuilder(this.endpointsServiceUri);
builder.Path += string.Format(CultureInfo.InvariantCulture, "/{0}/{1}", this.applicationId, this.deviceId);
builder.Path += string.Format(
CultureInfo.InvariantCulture,
"/{0}/{1}",
this.applicationId,
this.clientId);
if (tileNavigationUri != null)
{
builder.Query = string.Format(
CultureInfo.InvariantCulture,
"tileId={0}",
tileNavigationUri.ToString());
}
var request = this.ResolveRequest(builder.Uri);
request.Method = "DELETE";
@ -190,10 +230,11 @@ namespace Microsoft.WindowsAzure.Samples.Phone.Notifications
if ((response != null) && (response.StatusCode == HttpStatusCode.Accepted))
{
this.DispatchCallback(callback, new PushRegistrationResponse(true, string.Empty));
this.notificationEndpoints.Remove(endpointIdentifier);
}
else
{
this.DispatchCallback(callback, new PushRegistrationResponse(false, "The push notification channel coud not be unregistered in the Endpoints service."));
this.DispatchCallback(callback, new PushRegistrationResponse(false, "The specified endpoint could not be unregistered in the Endpoints service."));
}
}
catch (WebException webException)
@ -203,6 +244,10 @@ namespace Microsoft.WindowsAzure.Samples.Phone.Notifications
},
null);
}
catch (InvalidOperationException exception)
{
this.DispatchCallback(callback, new PushRegistrationResponse(false, exception.Message));
}
catch (ArgumentNullException exception)
{
this.DispatchCallback(callback, new PushRegistrationResponse(false, exception.Message));

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

@ -42,6 +42,8 @@ namespace Microsoft.WindowsAzure.Samples.Phone.Notifications
public string ApplicationId { get; set; }
public string DeviceId { get; set; }
public string ClientId { get; set; }
public string DeviceType { get; set; }
}
}
}

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

@ -109,7 +109,7 @@ namespace Microsoft.WindowsAzure.Samples.Phone.Notifications
public IPushClient ResolvePushClient()
{
return new PushClient(this.Configuration.EndpointsServiceUri, this.Configuration.SignRequest, this.Configuration.ApplicationId, this.Configuration.DeviceId, this.Configuration.Dispatcher);
return new PushClient(this.Configuration.EndpointsServiceUri, this.Configuration.SignRequest, this.Configuration.ApplicationId, this.Configuration.ClientId, this.Configuration.DeviceType, this.Configuration.Dispatcher);
}
public void Connect(Action<HttpNotificationChannel> callback)
@ -126,6 +126,7 @@ namespace Microsoft.WindowsAzure.Samples.Phone.Notifications
{
// First, try to pick up an existing channel.
this.NotificationChannel = HttpNotificationChannel.Find(this.config.ChannelName);
if (this.NotificationChannel == null)
{
this.CreateChannel(callback);

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

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

@ -31,6 +31,8 @@
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -124,6 +126,7 @@
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.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">