Skip to content

Commit 6ce9710

Browse files
committed
Added Source Code
Source Code for Client side app to that enables wcf service that allows to call scanner from web browser
1 parent ab3909f commit 6ce9710

File tree

56 files changed

+1594
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1594
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{CD47E419-3765-44DE-B403-7B48D4B0FDFA}</ProjectGuid>
8+
<OutputType>Library</OutputType>
9+
<AppDesignerFolder>Properties</AppDesignerFolder>
10+
<RootNamespace>CORS.Enabled</RootNamespace>
11+
<AssemblyName>CORS.Enabled</AssemblyName>
12+
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
13+
<FileAlignment>512</FileAlignment>
14+
</PropertyGroup>
15+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16+
<DebugSymbols>true</DebugSymbols>
17+
<DebugType>full</DebugType>
18+
<Optimize>false</Optimize>
19+
<OutputPath>bin\Debug\</OutputPath>
20+
<DefineConstants>DEBUG;TRACE</DefineConstants>
21+
<ErrorReport>prompt</ErrorReport>
22+
<WarningLevel>4</WarningLevel>
23+
</PropertyGroup>
24+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
25+
<DebugType>pdbonly</DebugType>
26+
<Optimize>true</Optimize>
27+
<OutputPath>bin\Release\</OutputPath>
28+
<DefineConstants>TRACE</DefineConstants>
29+
<ErrorReport>prompt</ErrorReport>
30+
<WarningLevel>4</WarningLevel>
31+
</PropertyGroup>
32+
<ItemGroup>
33+
<Reference Include="System" />
34+
<Reference Include="System.Core" />
35+
<Reference Include="System.ServiceModel" />
36+
<Reference Include="System.ServiceModel.Activation" />
37+
<Reference Include="System.ServiceModel.Web" />
38+
<Reference Include="System.Xml.Linq" />
39+
<Reference Include="System.Data.DataSetExtensions" />
40+
<Reference Include="Microsoft.CSharp" />
41+
<Reference Include="System.Data" />
42+
<Reference Include="System.Net.Http" />
43+
<Reference Include="System.Xml" />
44+
</ItemGroup>
45+
<ItemGroup>
46+
<Compile Include="CorsConstants.cs" />
47+
<Compile Include="CorsEnabledAttribute.cs" />
48+
<Compile Include="CorsEnabledMessageInspector.cs" />
49+
<Compile Include="CorsEnabledServiceHostFactory.cs" />
50+
<Compile Include="EnableCorsEndpointBehavior.cs" />
51+
<Compile Include="PreflightOperationBehavior.cs" />
52+
<Compile Include="PreflightOperationInvoker.cs" />
53+
<Compile Include="Properties\AssemblyInfo.cs" />
54+
</ItemGroup>
55+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
56+
</Project>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<ProjectView>ShowAllFiles</ProjectView>
5+
</PropertyGroup>
6+
</Project>

src/CORS.Enabled/CorsConstants.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace CorsEnabledService
8+
{
9+
class CorsConstants
10+
{
11+
internal const string Origin = "Origin";
12+
internal const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
13+
internal const string AccessControlRequestMethod = "Access-Control-Request-Method";
14+
internal const string AccessControlRequestHeaders = "Access-Control-Request-Headers";
15+
internal const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
16+
internal const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
17+
internal const string PreflightSuffix = "_preflight_";
18+
}
19+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.ServiceModel.Channels;
5+
using System.ServiceModel.Description;
6+
using System.ServiceModel.Dispatcher;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
10+
namespace CorsEnabledService
11+
{
12+
public class CorsEnabledAttribute : Attribute, IOperationBehavior
13+
{
14+
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
15+
{
16+
}
17+
18+
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
19+
{
20+
}
21+
22+
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
23+
{
24+
}
25+
26+
public void Validate(OperationDescription operationDescription)
27+
{
28+
}
29+
}
30+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.ServiceModel;
5+
using System.ServiceModel.Channels;
6+
using System.ServiceModel.Description;
7+
using System.ServiceModel.Dispatcher;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
11+
namespace CorsEnabledService
12+
{
13+
class CorsEnabledMessageInspector : IDispatchMessageInspector
14+
{
15+
private List<string> corsEnabledOperationNames;
16+
17+
public CorsEnabledMessageInspector(List<OperationDescription> corsEnabledOperations)
18+
{
19+
this.corsEnabledOperationNames = corsEnabledOperations.Select(o => o.Name).ToList();
20+
}
21+
22+
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
23+
{
24+
HttpRequestMessageProperty httpProp = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
25+
object operationName;
26+
request.Properties.TryGetValue(WebHttpDispatchOperationSelector.HttpOperationNamePropertyName, out operationName);
27+
if (httpProp != null && operationName != null && this.corsEnabledOperationNames.Contains((string)operationName))
28+
{
29+
string origin = httpProp.Headers[CorsConstants.Origin];
30+
if (origin != null)
31+
{
32+
return origin;
33+
}
34+
}
35+
36+
return null;
37+
}
38+
39+
public void BeforeSendReply(ref Message reply, object correlationState)
40+
{
41+
string origin = correlationState as string;
42+
if (origin != null)
43+
{
44+
HttpResponseMessageProperty httpProp = null;
45+
if (reply.Properties.ContainsKey(HttpResponseMessageProperty.Name))
46+
{
47+
httpProp = (HttpResponseMessageProperty)reply.Properties[HttpResponseMessageProperty.Name];
48+
}
49+
else
50+
{
51+
httpProp = new HttpResponseMessageProperty();
52+
reply.Properties.Add(HttpResponseMessageProperty.Name, httpProp);
53+
}
54+
55+
httpProp.Headers.Add(CorsConstants.AccessControlAllowOrigin, origin);
56+
}
57+
}
58+
}
59+
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.ServiceModel;
5+
using System.ServiceModel.Activation;
6+
using System.ServiceModel.Channels;
7+
using System.ServiceModel.Description;
8+
using System.ServiceModel.Web;
9+
using System.Text;
10+
using System.Threading.Tasks;
11+
12+
namespace CorsEnabledService
13+
{
14+
public class CorsEnabledServiceHostFactory : ServiceHostFactory
15+
{
16+
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
17+
{
18+
return new CorsEnabledServiceHost(serviceType, baseAddresses);
19+
}
20+
}
21+
22+
public class CorsEnabledServiceHost : ServiceHost
23+
{
24+
Type contractType;
25+
public CorsEnabledServiceHost(Type serviceType, params Uri[] baseAddresses)
26+
: base(serviceType, baseAddresses)
27+
{
28+
this.contractType = GetContractType(serviceType);
29+
}
30+
31+
protected override void OnOpening()
32+
{
33+
ServiceEndpoint endpoint = this.AddServiceEndpoint(this.contractType, new WebHttpBinding(), "");
34+
35+
List<OperationDescription> corsEnabledOperations = endpoint.Contract.Operations
36+
.Where(o => o.Behaviors.Find<CorsEnabledAttribute>() != null)
37+
.ToList();
38+
39+
AddPreflightOperations(endpoint, corsEnabledOperations);
40+
41+
var webHttpBheavior = new WebHttpBehavior();
42+
webHttpBheavior.HelpEnabled = true;
43+
endpoint.Behaviors.Add(webHttpBheavior);
44+
endpoint.Behaviors.Add(new EnableCorsEndpointBehavior());
45+
46+
base.OnOpening();
47+
}
48+
49+
private Type GetContractType(Type serviceType)
50+
{
51+
if (HasServiceContract(serviceType))
52+
{
53+
return serviceType;
54+
}
55+
56+
Type[] possibleContractTypes = serviceType.GetInterfaces()
57+
.Where(i => HasServiceContract(i))
58+
.ToArray();
59+
60+
switch (possibleContractTypes.Length)
61+
{
62+
case 0:
63+
throw new InvalidOperationException("Service type " + serviceType.FullName + " does not implement any interface decorated with the ServiceContractAttribute.");
64+
case 1:
65+
return possibleContractTypes[0];
66+
default:
67+
throw new InvalidOperationException("Service type " + serviceType.FullName + " implements multiple interfaces decorated with the ServiceContractAttribute, not supported by this factory.");
68+
}
69+
}
70+
71+
private static bool HasServiceContract(Type type)
72+
{
73+
return Attribute.IsDefined(type, typeof(ServiceContractAttribute), false);
74+
}
75+
76+
private void AddPreflightOperations(ServiceEndpoint endpoint, List<OperationDescription> corsOperations)
77+
{
78+
Dictionary<string, PreflightOperationBehavior> uriTemplates = new Dictionary<string, PreflightOperationBehavior>(StringComparer.OrdinalIgnoreCase);
79+
80+
foreach (var operation in corsOperations)
81+
{
82+
if (operation.Behaviors.Find<WebGetAttribute>() != null)
83+
{
84+
// no need to add preflight operation for GET requests
85+
continue;
86+
}
87+
88+
if (operation.IsOneWay)
89+
{
90+
// no support for 1-way messages
91+
continue;
92+
}
93+
94+
string originalUriTemplate;
95+
WebInvokeAttribute originalWia = operation.Behaviors.Find<WebInvokeAttribute>();
96+
97+
if (originalWia != null && originalWia.UriTemplate != null)
98+
{
99+
originalUriTemplate = NormalizeTemplate(originalWia.UriTemplate);
100+
}
101+
else
102+
{
103+
originalUriTemplate = operation.Name;
104+
}
105+
106+
string originalMethod = originalWia != null && originalWia.Method != null ? originalWia.Method : "POST";
107+
108+
if (uriTemplates.ContainsKey(originalUriTemplate))
109+
{
110+
// there is already an OPTIONS operation for this URI, we can reuse it
111+
PreflightOperationBehavior operationBehavior = uriTemplates[originalUriTemplate];
112+
operationBehavior.AddAllowedMethod(originalMethod);
113+
}
114+
else
115+
{
116+
ContractDescription contract = operation.DeclaringContract;
117+
OperationDescription preflightOperation = new OperationDescription(operation.Name + CorsConstants.PreflightSuffix, contract);
118+
MessageDescription inputMessage = new MessageDescription(operation.Messages[0].Action + CorsConstants.PreflightSuffix, MessageDirection.Input);
119+
inputMessage.Body.Parts.Add(new MessagePartDescription("input", contract.Namespace) { Index = 0, Type = typeof(Message) });
120+
preflightOperation.Messages.Add(inputMessage);
121+
MessageDescription outputMessage = new MessageDescription(operation.Messages[1].Action + CorsConstants.PreflightSuffix, MessageDirection.Output);
122+
outputMessage.Body.ReturnValue = new MessagePartDescription(preflightOperation.Name + "Return", contract.Namespace) { Type = typeof(Message) };
123+
preflightOperation.Messages.Add(outputMessage);
124+
125+
WebInvokeAttribute wia = new WebInvokeAttribute();
126+
wia.UriTemplate = originalUriTemplate;
127+
wia.Method = "OPTIONS";
128+
129+
preflightOperation.Behaviors.Add(wia);
130+
preflightOperation.Behaviors.Add(new DataContractSerializerOperationBehavior(preflightOperation));
131+
PreflightOperationBehavior preflightOperationBehavior = new PreflightOperationBehavior(preflightOperation);
132+
preflightOperationBehavior.AddAllowedMethod(originalMethod);
133+
preflightOperation.Behaviors.Add(preflightOperationBehavior);
134+
uriTemplates.Add(originalUriTemplate, preflightOperationBehavior);
135+
136+
contract.Operations.Add(preflightOperation);
137+
}
138+
}
139+
}
140+
141+
private string NormalizeTemplate(string uriTemplate)
142+
{
143+
int queryIndex = uriTemplate.IndexOf('?');
144+
if (queryIndex >= 0)
145+
{
146+
// no query string used for this
147+
uriTemplate = uriTemplate.Substring(0, queryIndex);
148+
}
149+
150+
int paramIndex;
151+
while ((paramIndex = uriTemplate.IndexOf('{')) >= 0)
152+
{
153+
// Replacing all named parameters with wildcards
154+
int endParamIndex = uriTemplate.IndexOf('}', paramIndex);
155+
if (endParamIndex >= 0)
156+
{
157+
uriTemplate = uriTemplate.Substring(0, paramIndex) + '*' + uriTemplate.Substring(endParamIndex + 1);
158+
}
159+
}
160+
161+
return uriTemplate;
162+
}
163+
}
164+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.ServiceModel.Channels;
5+
using System.ServiceModel.Description;
6+
using System.ServiceModel.Dispatcher;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
10+
namespace CorsEnabledService
11+
{
12+
class EnableCorsEndpointBehavior : IEndpointBehavior
13+
{
14+
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
15+
{
16+
}
17+
18+
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
19+
{
20+
}
21+
22+
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
23+
{
24+
List<OperationDescription> corsEnabledOperations = endpoint.Contract.Operations
25+
.Where(o => o.Behaviors.Find<CorsEnabledAttribute>() != null)
26+
.ToList();
27+
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new CorsEnabledMessageInspector(corsEnabledOperations));
28+
}
29+
30+
public void Validate(ServiceEndpoint endpoint)
31+
{
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)