Skip to content

Commit

Permalink
Bug fix in WCF integration.
Browse files Browse the repository at this point in the history
WCF integration failed to create WCF services marked with
InstanceContextMode.Single. (fixes #197)
  • Loading branch information
dotnetjunkie committed Apr 9, 2016
1 parent 3934858 commit 1623a17
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SimpleInjector.Integration.Wcf</RootNamespace>
<AssemblyName>SimpleInjector.Integration.Wcf</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
Expand Down
20 changes: 19 additions & 1 deletion src/SimpleInjector.Integration.Wcf/SimpleInjectorServiceHost.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#region Copyright Simple Injector Contributors
/* The Simple Injector is an easy-to-use Inversion of Control library for .NET
*
* Copyright (c) 2013 Simple Injector Contributors
* Copyright (c) 2013-2016 Simple Injector Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including
Expand Down Expand Up @@ -52,6 +52,24 @@ public SimpleInjectorServiceHost(Container container, Type serviceType, params U
this.container = container;
}

/// <summary>
/// Initializes a new instance of the <see cref="SimpleInjectorServiceHost"/> class.
/// </summary>
/// <param name="container">The container.</param>
/// <param name="singletonInstance">The instance of the hosted service.</param>
/// <param name="baseAddresses">The base addresses.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="container"/> is a null
/// reference or <paramref name="singletonInstance"/> is a null reference.</exception>
public SimpleInjectorServiceHost(Container container, object singletonInstance,
params Uri[] baseAddresses)
: base(singletonInstance, baseAddresses)
{
Requires.IsNotNull(container, nameof(container));
Requires.IsNotNull(singletonInstance, nameof(singletonInstance));

this.container = container;
}

/// <summary>Gets the contracts implemented by the service hosted.</summary>
/// <returns>The collection of <see cref="ContractDescription"/>s.</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#region Copyright Simple Injector Contributors
/* The Simple Injector is an easy-to-use Inversion of Control library for .NET
*
* Copyright (c) 2013 Simple Injector Contributors
* Copyright (c) 2013-2016 Simple Injector Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including
Expand All @@ -23,7 +23,7 @@
namespace SimpleInjector.Integration.Wcf
{
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;

Expand Down Expand Up @@ -82,7 +82,49 @@ protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAdd
"documentation: https://simpleinjector.org/wcf.");
}

return new SimpleInjectorServiceHost(container, serviceType, baseAddresses);
if (GetInstanceContextMode(serviceType) == InstanceContextMode.Single)
{
object singletonInstance = GetSingletonInstance(serviceType);

return new SimpleInjectorServiceHost(container, singletonInstance, baseAddresses);
}
else
{
return new SimpleInjectorServiceHost(container, serviceType, baseAddresses);
}
}

private static InstanceContextMode GetInstanceContextMode(Type serviceType)
{
var behavior = serviceType.GetCustomAttributes(typeof(ServiceBehaviorAttribute), true)
.OfType<ServiceBehaviorAttribute>()
.FirstOrDefault();

return behavior?.InstanceContextMode ?? InstanceContextMode.PerCall;
}

private static object GetSingletonInstance(Type serviceType)
{
InstanceProducer registration = container.GetRegistration(serviceType);

// Call GetInstance BEFORE checking the Lifestyle property; decorators might be applied at this
// point, causing the lifestyle and registration properties to change.
object singletonInstance = registration.GetInstance();

if (registration.Lifestyle != Lifestyle.Singleton)
{
throw new InvalidOperationException(string.Format(
"Service type {0} has been flagged as 'Single' using the ServiceBehaviorAttribute, " +
"causing WCF to hold on to this instance indefinitely, while {1} has been registered " +
"with the {2} lifestyle in the container. Please make sure that {1} is registered " +
"as Singleton as well, or mark {0} with " +
"[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] instead.",
serviceType.FullName,
registration.Registration.ImplementationType.FullName,
registration.Lifestyle.Name));
}

return singletonInstance;
}
}
}
1 change: 1 addition & 0 deletions src/changes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Version 3.1.3 (v3.1.3 RTM)
Bug fixes:
-[Core] Registration of conditional closed-generic types prevented when container allows
overriding registrations. (fixes #216)
-[WCF] WCF integration failed to create WCF services marked with InstanceContextMode.Single. (fixes #197)


Version 3.1.2 (v3.1.2 RTM) 2015-12-13
Expand Down

0 comments on commit 1623a17

Please sign in to comment.