Is this a Appropriate method to safely close a proxy on WCF-calls? - wcf

In my application i discovered that sometimes the Close() for a WCF-call/channels trowed errors.
And i did a little research on the subject and borrowed some code on the internet to get me started.
And now, I wonder is this the right way to go? or should i improve the solution or maybe implement something totally different?
Generic-Class/Static Class:
public class SafeProxy<Service> : IDisposable where Service : ICommunicationObject
{
private readonly Service _proxy;
public SafeProxy(Service s)
{
_proxy = s;
}
public Service Proxy
{
get { return _proxy; }
}
public void Dispose()
{
if (_proxy != null)
_proxy.SafeClose();
}
}
public static class Safeclose
{
public static void SafeClose(this ICommunicationObject proxy)
{
try
{
proxy.Close();
}
catch
{
proxy.Abort();
}
}
}
This is how i make calls to the WCF:
(The WCFReference is a Service Reference pointing to the WCF service adress)
using (var Client = new SafeProxy<WCFReference.ServiceClient>(new WCFReference.ServiceClient()))
{
Client.Proxy.Operation(info);
}

Here's a quick little extension method I use to safely interact with a WCF service from the client:
/// <summary>
/// Helper class for WCF clients.
/// </summary>
internal static class WcfClientUtils
{
/// <summary>
/// Executes a method on the specified WCF client.
/// </summary>
/// <typeparam name="T">The type of the WCF client.</typeparam>
/// <typeparam name="TU">The return type of the method.</typeparam>
/// <param name="client">The WCF client.</param>
/// <param name="action">The method to execute.</param>
/// <returns>A value from the executed method.</returns>
/// <exception cref="CommunicationException">A WCF communication exception occurred.</exception>
/// <exception cref="TimeoutException">A WCF timeout exception occurred.</exception>
/// <exception cref="Exception">Another exception type occurred.</exception>
public static TU Execute<T, TU>(this T client, Func<T, TU> action) where T : class, ICommunicationObject
{
if ((client == null) || (action == null))
{
return default(TU);
}
try
{
return action(client);
}
catch (CommunicationException)
{
client.Abort();
throw;
}
catch (TimeoutException)
{
client.Abort();
throw;
}
catch
{
if (client.State == CommunicationState.Faulted)
{
client.Abort();
}
throw;
}
finally
{
try
{
if (client.State != CommunicationState.Faulted)
{
client.Close();
}
}
catch
{
client.Abort();
}
}
}
}
I call it as such:
var result = new WCFReference.ServiceClient().Execute(client => client.Operation(info));

Related

Ninject Interception in a IIS hosted WCF application

I have a working WCF application hosted in IIS (.svc), using Ninject (Ninject.Web.Common) for dependency injection. All is well and good, works great. However I am trying to implment interception on the service endpoints and am getting a ServiceActiviationException. I've included the ninject extensions for wcf, interception, and interception.dynamic proxy as well as castle.core, so I'm not really sure what I'm missing here. Any ideas?
UPDATE: I was able to get past the service validation exception but I am now getting the following error:
Can not instantiate proxy of class: MyNameSpace.CustomerService.
Could not find a parameterless constructor.
My NinjectWebCommon contents:
public class NinjectWebCommon
{
private static readonly Bootstrapper Bootstrapper = new Bootstrapper();
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
Bootstrapper.Initialize(CreateKernel);
}
public static void PostStart()
{
// Inject the WITS Application Security service into the ApplicationSecurityRoleProvider
//_kernel.Inject(Roles.Provider);
}
public static void Stop()
{
Bootstrapper.ShutDown();
}
private static IKernel CreateKernel()
{
var kernel = new StandardKernel(
new AutoMapperModule(),
new CustomerServiceModule(),
new AccountServiceModule());
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<LoggingInterceptor>().ToSelf().InRequestScope();
kernel.Bind<CustomerService>().ToSelf().Intercept().With<LoggingInterceptor>();
}
And a simple interceptor (Ive tried this also just implementing IInterceptor to no avail):
public class LoggingInterceptor : SimpleInterceptor
{
/// <summary>
/// Intercepts the specified invocation.
/// </summary>
/// <param name="invocation">The invocation to intercept.</param>
protected override void BeforeInvoke(IInvocation invocation)
{
Debug.WriteLine("Running " + invocation.ReturnValue);
base.BeforeInvoke(invocation);
}
public new void Intercept(IInvocation invocation)
{
try
{
base.Intercept(invocation);
}
catch (Exception e)
{
Debug.WriteLine("Exception: " + e.Message);
}
}
protected override void AfterInvoke(IInvocation invocation)
{
Debug.WriteLine("After Method");
base.AfterInvoke(invocation);
}
}

Selenium Tests Failing when running them all in one go

I have the below code which initiates the browser in each test. However the first Test runs OK correctly starting the browser. The second Test on wards start to fail
public class BrowserFactory
{
private static IWebDriver driver;
public static IWebDriver Driver
{
get
{
if (driver == null)
throw new NullReferenceException("The WebDriver browser instance was not initialized. You should first call the method InitBrowser.");
return driver;
}
set
{
driver = value;
}
}
public static void InitBrowser(string browserName)
{
switch (browserName)
{
case "Firefox":
if (driver == null)
{
driver = new FirefoxDriver();
driver.Manage().Window.Maximize();
}
break;
case "IE":
if (driver == null)
{
driver = new InternetExplorerDriver();
driver.Manage().Window.Maximize();
}
break;
case "Chrome":
if (driver == null)
{
driver = new ChromeDriver();
driver.Manage().Window.Maximize();
}
break;
}
}
And this is how I initiate and quit browser in each test
[TestFixture]
public class AdminUserHasAccessToDashboard
{
[SetUp]
public void GotoHomePage()
{
BrowserFactory.InitBrowser("Chrome");
BrowserFactory.LoadApplication(ConfigurationManager.AppSettings["URL"]);
}
[TearDown]
public void Quit()
{
BrowserFactory.CloseAllDrivers();
}
It looks like you are probably setting driver instance in your first test and other tests are false on if (driver == null), so other instances will never be created. Your code is incomplete so I can't be sure, but it seems to be an issue here.
How are you closing your driver after first test is completed?
Include the method mentioned below in your browser factory and call at the end of each test, or set up before the tests are run then use the single instance for each test and tear down at the end.
public static void Quit(){
if (Driver!= null)
Driver.Quit();
}
I use a static "Driver" class which is referenced in each test class (not each test case)
I include this in each class(they are nunit C# tests)
#region Initialise and clean up
[OneTimeSetUp]
public void Init()
{
Driver.Initialise();
}
[OneTimeTearDown]
public void CleanUp()
{
Driver.Quit();
}
#endregion
Then my driver class is as below, the appstate region wont apply but can be edited to suit your needs.
using System;
using System.Threading;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using AdaptiveAds_TestFramework.PageFrameworks;
namespace AdaptiveAds_TestFramework.Helpers
{
/// <summary>
/// Contains functionality for browser automation.
/// </summary>
public static class Driver
{
#region Variables
private static IWebDriver _instance;
private static Period _waitPeriod;
#endregion//Variables
#region Properties
/// <summary>
/// Browser automation object.
/// </summary>
public static IWebDriver Instance
{
get { return _instance; }
set { _instance = value; SetWait(WaitPeriod); }
}
/// <summary>
/// Duration automation framework must wait before throwing an error.
/// </summary>
public static Period WaitPeriod
{
get { return _waitPeriod; }
set
{
_waitPeriod = value;
SetWait(_waitPeriod);
}
}
#endregion//Properties
#region Methods
#region set-up and tear-down
/// <summary>
/// Sets up a new automation object.
/// </summary>
public static void Initialise()
{
Quit();
Instance = new FirefoxDriver(new FirefoxBinary(ConfigData.FireFoxPath), new FirefoxProfile());
Instance.Manage().Window.Maximize();
WaitPeriod = ConfigData.DefaultWaitPeriod;
}
/// <summary>
/// Disposes of the automation object.
/// </summary>
public static void Quit()
{
if (Instance != null)
Instance.Quit();
}
#endregion //set-up and tear-down
#region NavigableLocations
/// <summary>
/// Navigate browser to a given location.
/// </summary>
/// <param name="location">Location to navigate to.</param>
/// <param name="logInIfNeeded">Logs in if authentication is required.</param>
/// <param name="errorIfNotReached">Errors if the location was not reached.</param>
public static void GoTo(Location location, bool logInIfNeeded, bool errorIfNotReached)
{
// Navigate browser to the location.
Instance.Navigate().GoToUrl(Helper.RouteUrl(location));
Thread.Sleep(500);// wait for system to navigate
bool needToLogIn = false;
if (logInIfNeeded)
{
try
{
IsAt(Location.Login);
needToLogIn = true;
}
catch
{
// Not at login page so Login not needed.
}
if (needToLogIn)
{
LoginPage.LoginAs(ConfigData.Username).WithPassword(ConfigData.Password).Login();
GoTo(location, false, errorIfNotReached);
}
}
if (errorIfNotReached)
{
IsAt(location);
}
}
/// <summary>
/// Ensures the Driver is at the specified location, throws a WebDriverException if at another location.
/// </summary>
/// <param name="location">Location to check the browser is at.</param>
public static void IsAt(Location location)
{
string expected = Helper.RouteUrl(location);
string actual = Instance.Url;
// Check the browser is at the correct location.
if (actual != expected)
{
// Driver is not at the specified location.
throw new WebDriverException("Incorrect location.",
new InvalidElementStateException(
"The given location did not match the browser." +
" Expected \"" + expected + "\" Actual \"" + actual + "\""));
}
ActionWait(Period.None, CheckForLavarelError);
}
/// <summary>
/// Ensures the Driver is not at the specified location, throws a WebDriverException if at the location.
/// </summary>
/// <param name="location">Location to check the browser is not at.</param>
public static void IsNotAt(Location location)
{
string expected = Helper.RouteUrl(location);
string actual = Instance.Url;
// Check the browser is not at the correct location.
if (actual == expected)
{
// Driver is at the specified location.
throw new WebDriverException("Incorrect location.",
new InvalidElementStateException(
"The given location matched the browser."));
}
}
#endregion//NavigableLocations
#region WaitHandling
/// <summary>
/// Performs an action with a temporary wait period.
/// </summary>
/// <param name="waitPeriod">Period to wait while executing action.</param>
/// <param name="action">Action to execute.</param>
public static void ActionWait(Period waitPeriod, Action action)
{
// Store the current wait period
Period previousPeriod = WaitPeriod;
// Run task with given wait period
SetWait(waitPeriod);
action();
// Revert to the old wait period
SetWait(previousPeriod);
}
/// <summary>
/// Updates the Automation instance wait period.
/// </summary>
/// <param name="waitPeriod">New wait period.</param>
private static void SetWait(Period waitPeriod)
{
int miliseconds;
ConfigData.WaitPeriods.TryGetValue(waitPeriod, out miliseconds);
// Set the drivers instance to use the wait period.
if (Instance != null)
{
Instance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromMilliseconds(miliseconds));
}
}
#endregion//WaitHandling
#region AppState
/// <summary>
/// Checks that the website hasn't crashed from the back end.
/// </summary>
public static void CheckForLavarelError()
{
bool error = false;
try
{
Instance.FindElement(By.ClassName("exception_message"));
error = true;
}
catch
{
// all good, could not find error content.
}
if (error)
{
throw new Exception("Lavarel threw an error");
}
}
/// <summary>
/// Clicks on the main menu button to open or close the main menu.
/// </summary>
public static void OpenCloseMenuBar()
{
try
{
IWebElement menuButton = Instance.FindElement(By.Name(ConfigData.MainMenuButtonName));
menuButton.Click();
}
catch (Exception e)
{
throw new NoSuchElementException("Could not find the Menu button element.", e);
}
}
/// <summary>
/// Asserts the logged in state agents the parameter.
/// </summary>
/// <param name="checkLoggedIn">Parameter to check agents logged in state.</param>
public static void LoggedIn(bool checkLoggedIn)
{
OpenCloseMenuBar();
bool signInFound;
bool signOutFound;
bool isLoggedIn = false;
try { Instance.FindElement(By.Name(ConfigData.SignInName)); signInFound = true; }
catch { signInFound = false; }
try { Instance.FindElement(By.Name(ConfigData.SignOutName)); signOutFound = true; }
catch { signOutFound = false; }
if (!signInFound && !signOutFound)
{
throw new ElementNotVisibleException("Unable to assert state due to unavailability of SignIn/Out links.");
}
if (signOutFound) isLoggedIn = true;
if (signInFound) isLoggedIn = false;
if (isLoggedIn != checkLoggedIn)
{
throw new Exception($"Logged in Expected: {checkLoggedIn} Actual: {isLoggedIn}");
}
}
/// <summary>
/// Signs out of the system.
/// </summary>
/// <param name="errorIfAlreadySignedOut">Determines whether to throw an error if already signed out.</param>
public static void SignOut(bool errorIfAlreadySignedOut = true)
{
try
{
LoggedIn(true);
}
catch (Exception)
{
if (errorIfAlreadySignedOut)
{
throw;
}
return;
}
IWebElement signOut = Instance.FindElement(By.Name(ConfigData.SignOutName));
signOut.Click();
Thread.Sleep(500);// wait for system to logout
}
#endregion//AppState
#endregion//Methods
}
}

Wcf NHibernate Session management

I'm new to Castle, NHibernate and WCF.
I implemented the session management for my MVC application based on the following article because it seemd to be the most advanced implementation of all posts I've read so far :
http://nhibernate.info/blog/2011/03/02/effective-nhibernate-session-management-for-web-apps.html
The only problem I got was that this uses some Asp.net specific functionality that isn't available in my WCF service like (HttpContext.Current.Items).
I started to use WcfFacility
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<WcfFacility>().Register
(
Component.For<IRepository>().ImplementedBy(typeof(RepositoryBase<,>)),
Component.For<ITimeService>()
.ImplementedBy<myTimeMvc.Webservice.TimeService>()
.Named("myTimeMvc.Webservice.TimeService"));
container.Register(
Component.For<IServiceBehavior>()
.ImplementedBy<WcfSessionPerRequestBehavior>()
);
}
My Persistance configuration:
public class PersistenceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Kernel.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<ISessionFactory>().UsingFactoryMethod(k => CreateNhSessionFactory()));
container.Register(Component.For<ISessionFactoryProvider>().AsFactory());
container.Register(Component.For<IEnumerable<ISessionFactory>>().UsingFactoryMethod(k => k.ResolveAll<ISessionFactory>()));
container.Register(Classes.FromAssembly(Assembly.GetAssembly(typeof(HdtRepository))).InSameNamespaceAs<HdtRepository>().WithService.DefaultInterfaces().LifestyleTransient());
}
/// <summary>
/// Creates NHibernate Session Factory.
/// </summary>
/// <returns>NHibernate Session Factory</returns>
private static ISessionFactory CreateNhSessionFactory()
{
var connStr = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
return Fluently.Configure()
.Database(
MsSqlConfiguration.MsSql2008
.UseOuterJoin()
.ConnectionString(x => x.FromConnectionStringWithKey("DefaultConnection"))
.ShowSql()
)
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<TimeRecord>())
.ExposeConfiguration(cfg =>
cfg.Properties[Environment.CurrentSessionContextClass] = typeof(LazySessionContext).AssemblyQualifiedName
)
.BuildSessionFactory();
}
}
Then i tried to solve the problem with "HttpContext.Current.Items" by adding a custom extension:
namespace MyTimeService.WcfExtension
{
///<summary>
/// This class incapsulates context information for a service instance
///</summary>
public class WcfInstanceContext : IExtension<InstanceContext>
{
private readonly IDictionary items;
private WcfInstanceContext()
{
items = new Hashtable();
}
///<summary>
/// <see cref="IDictionary"/> stored in current instance context.
///</summary>
public IDictionary Items
{
get { return items; }
}
///<summary>
/// Gets the current instance of <see cref="WcfInstanceContext"/>
///</summary>
public static WcfInstanceContext Current
{
get
{
WcfInstanceContext context = OperationContext.Current.InstanceContext.Extensions.Find<WcfInstanceContext>();
if (context == null)
{
context = new WcfInstanceContext();
OperationContext.Current.InstanceContext.Extensions.Add(context);
}
return context;
}
}
/// <summary>
/// <see cref="IExtension{T}"/> Attach() method
/// </summary>
public void Attach(InstanceContext owner) { }
/// <summary>
/// <see cref="IExtension{T}"/> Detach() method
/// </summary>
public void Detach(InstanceContext owner) { }
}
}
registered the following way:
<extensions>
<behaviorExtensions>
<add name="WcfInstanceContext" type="MyTimeService.WcfExtension, MyTimeService.WcfExtension.WcfInstanceContext" />
</behaviorExtensions>
</extensions>
Then I created a custom ServiceBehavior
public class WcfSessionPerRequestBehavior : IServiceBehavior
{
private ISessionFactoryProvider _sfp;
public WcfSessionPerRequestBehavior(ISessionFactoryProvider sfp)
{
_sfp = sfp;
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (var cdb in serviceHostBase.ChannelDispatchers)
{
var channelDispatcher = cdb as ChannelDispatcher;
if (null != channelDispatcher)
{
foreach (var endpointDispatcher in channelDispatcher.Endpoints)
{
foreach (var dispatchOperation in endpointDispatcher.DispatchRuntime.Operations)
{
dispatchOperation.CallContextInitializers.Add(new WcfSessionPerRequestCallContextInitializer(_sfp));
}
}
}
}
}
followed by a custom ICallContextInitializer:
public class WcfSessionPerRequestCallContextInitializer : ICallContextInitializer
{
private ILogger logger = NullLogger.Instance;
public ILogger Logger
{
get { return logger; }
set { logger = value; }
}
private ISessionFactoryProvider sfp;
public WcfSessionPerRequestCallContextInitializer(ISessionFactoryProvider s)
{
this.sfp = s;
}
public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
{
foreach (var sf in sfp.GetSessionFactories())
{
var localFactory = sf;
LazySessionContext.Bind(new Lazy<NHibernate.ISession>(() => BeginSession(localFactory)), sf);
}
return null;
}
public void AfterInvoke(object correlationState)
{
foreach (var sf in sfp.GetSessionFactories())
{
var session = LazySessionContext.UnBind(sf);
if (session == null) continue;
EndSession(session);
}
}
private static NHibernate.ISession BeginSession(ISessionFactory sf)
{
var session = sf.OpenSession();
session.BeginTransaction();
return session;
}
private void ContextEndRequest(object sender, EventArgs e)
{
foreach (var sf in sfp.GetSessionFactories())
{
var session = LazySessionContext.UnBind(sf);
if (session == null) continue;
EndSession(session);
}
}
private static void EndSession(NHibernate.ISession session)
{
if (session.Transaction != null && session.Transaction.IsActive)
{
session.Transaction.Commit();
}
session.Dispose();
}
}
and at last I adjusted the ICurrentSessionContext:
public class LazySessionContext : ICurrentSessionContext
{
private readonly ISessionFactoryImplementor factory;
private const string CurrentSessionContextKey = "NHibernateCurrentSession";
public LazySessionContext(ISessionFactoryImplementor factory)
{
this.factory = factory;
}
/// <summary>
/// Retrieve the current session for the session factory.
/// </summary>
/// <returns></returns>
public NHibernate.ISession CurrentSession()
{
Lazy<NHibernate.ISession> initializer;
var currentSessionFactoryMap = GetCurrentFactoryMap();
if (currentSessionFactoryMap == null || !currentSessionFactoryMap.TryGetValue(factory, out initializer))
{
return null;
}
return initializer.Value;
}
/// <summary>
/// Bind a new sessionInitializer to the context of the sessionFactory.
/// </summary>
/// <param name="sessionInitializer"></param>
/// <param name="sessionFactory"></param>
public static void Bind(Lazy<NHibernate.ISession> sessionInitializer, ISessionFactory sessionFactory)
{
var map = GetCurrentFactoryMap();
map[sessionFactory] = sessionInitializer;
}
/// <summary>
/// Unbind the current session of the session factory.
/// </summary>
/// <param name="sessionFactory"></param>
/// <returns></returns>
public static NHibernate.ISession UnBind(ISessionFactory sessionFactory)
{
var map = GetCurrentFactoryMap();
var sessionInitializer = map[sessionFactory];
map[sessionFactory] = null;
if (sessionInitializer == null || !sessionInitializer.IsValueCreated) return null;
return sessionInitializer.Value;
}
/// <summary>
/// Provides the CurrentMap of SessionFactories.
/// If there is no map create/store and return a new one.
/// </summary>
/// <returns></returns>
private static IDictionary<ISessionFactory, Lazy<NHibernate.ISession>> GetCurrentFactoryMap()
{
//var currentFactoryMap = (IDictionary<ISessionFactory, Lazy<NHibernate.ISession>>)HttpContext.Current.Items[CurrentSessionContextKey];
var currentFactoryMap = (IDictionary<ISessionFactory, Lazy<NHibernate.ISession>>)WcfInstanceContext.Current.Items[CurrentSessionContextKey];
if (currentFactoryMap == null)
{
currentFactoryMap = new Dictionary<ISessionFactory, Lazy<NHibernate.ISession>>();
WcfInstanceContext.Current.Items[CurrentSessionContextKey] = currentFactoryMap;
}
return currentFactoryMap;
}
}
This seems to work but since I'm new to all that stuff I can't say if I did this corretly.
Can anyone have a look at it and give me feedback?
Cheers,
Stefan
Your are using OperationContext.Current which is the correct way to do per request context implementations for WCF services, so it looks good to me...
Question is, why are you not simply using the default implementation which comes out of the box with nhibernate? The implementation is in NHibernate.Context.WcfOperationSessionContext and you would just have to use this one within your session factory setup
For example:
Fluently.Configure()
...
.ExposeConfiguration(cfg => cfg.SetProperty(
Environment.CurrentSessionContextClass,
"wcf")
or Fluently.Configure()...CurrentSessionContext<WcfOperationSessionContext>()
You could also simply setaspNetCompatibilityEnabled=true and you will get HttpContext available to both MVC and WCF.

NHibernate Invalid Index Exception

I´m developing an ASP.NET MVC Application, in which I use NHibernate and Ninject.
The Problem is caused by the following Controller:
public class ShoppingCartController : Controller
{
private readonly Data.Infrastructure.IShoppingCartRepository _shoppingCartRepository;
private readonly Data.Infrastructure.IShopItemRepository _shopItemRepository;
public ShoppingCartController(Data.Infrastructure.IShoppingCartRepository shoppingCartController,
Data.Infrastructure.IShopItemRepository shopItemRepository)
{
_shoppingCartRepository = shoppingCartController;
_shopItemRepository = shopItemRepository;
}
public ActionResult AddToShoppingCart(FormCollection formCollection)
{
var cartItem = new Data.Models.ShoppingCartItem();
cartItem.ChangeDate = DateTime.Now;
cartItem.ShopItem = _shopItemRepository.GetShopItem(SessionData.Data.Info, Convert.ToInt32(formCollection["shopItemId"]));
//IF I DONT´T CALL THE METHOD ABOVE, AddToCart works
_shoppingCartRepository.AddToCart(SessionData.Data.Info, cartItem);
//BUT IF I CALL THE GetShopItem METHOD I GET THE EXCEPTION HERE!
return RedirectToAction("Index", "Shop");
}
}
I know most of the Time this Exception is caused by wrong Mapping, but I´m pretty sure that my Mapping is right because the AddToCart-Method works if I don´t call GetShopItem...
So here is the Code of the ShopItemRepository:
public class ShopItemRepository : ReadOnlyRepository<ShopItem>, IShopItemRepository
{
public ShopItemRepository(IUnitOfWork uow) : base(uow)
{
}
public ShopItem GetShopItem(SessionParams param, int id)
{
return CurrentSession.QueryOver<ShopItem>()
.Where(x => x.ProcessId == param.ProcessId &&
x.CatalogueId == param.CatalogueId &&
x.Id == id)
.SingleOrDefault();
}
public IList<ShopItem> GetShopItems(SessionParams param)
{
return CurrentSession.GetNamedQuery("GetShopItems")
.SetParameter("requestor_id", param.RequestorId)
.SetParameter("recipient_id", param.RecipientId)
.SetParameter("process_id", param.ProcessId)
.SetParameter("catalogue_id", param.CatalogueId)
.List<ShopItem>();
}
}
And finally the Code of my UnitOfWork (basically it is just a Wrapper for the Session because I don´t want to reference NHibernate in my MVC Project)
public class UnitOfWork : IUnitOfWork, IDisposable
{
private NHibernate.ISession _currentSession;
public NHibernate.ISession CurrentSession
{
get
{
if(_currentSession == null)
{
_currentSession = SessionFactoryWrapper.SessionFactory.OpenSession();
}
return _currentSession;
}
}
public void Dispose()
{
if(_currentSession != null)
{
_currentSession.Close();
_currentSession.Dispose();
_currentSession = null;
}
GC.SuppressFinalize(this);
}
}
Addendum:
My NinjectWebCommon Class
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
kernel.Bind<Data.Infrastructure.ICatalogueRepository>().To<Data.Repositories.CatalogueRepository>();
kernel.Bind<Data.Infrastructure.ICategoryRepository>().To<Data.Repositories.CategoryRepository>();
kernel.Bind<Data.Infrastructure.IContactRepository>().To<Data.Repositories.ContactRepository>();
kernel.Bind<Data.Infrastructure.IProcessRepository>().To<Data.Repositories.ProcessRepository>();
kernel.Bind<Data.Infrastructure.IShopItemRepository>().To<Data.Repositories.ShopItemRepository>();
kernel.Bind<Data.Infrastructure.IShoppingCartRepository>().To<Data.Repositories.ShoppingCartRepository>();
}
}
IUnitOfWork is set to RequestScope so in the Case of ShoppingCartController, the two Repositories share the same UOW right?
Maybe this could cause the Problem?
Are you sure that this isn´t caused by wrong mapping? I had the same Issue and could resolve it by checking my mappings again!

WCF FaultContract Fails with NamedPipe

I have a simple IPC mechanism that uses WCF and named pipes. My goal is to propagate exception details (including the stacktrace) to the client for logging purposes (the rest of the application logging is located on the client).
If I use the following code I am able to catch FaultException<Exception> on the client and see exception details:
Contract:
[ServiceContract]
public interface IService
{
[OperationContract]
[FaultContract(typeof(Exception))]
void DoSomething();
}
Implementation:
public class Service : IService
{
public void DoSomething()
{
try
{
ThisWillThrowAnException();
}
catch (Exception e)
{
throw new FaultException<Exception>(e);
}
}
}
Client:
public void CallServer()
{
try
{
proxy.DoSomething();
}
catch (FaultException<Exception> e)
{
Console.WriteLine("Caught fault exception!");
}
}
This works fine and I see the message printed on the console. However, if I want to use my own derived exception instead of the base Exception class, it fails.
Custom Exception:
[Serializable]
public class MyException : Exception
{
public MyException () { }
public MyException (string message) : base(message) { }
public MyException (string message, Exception inner) : base(message, inner) { }
protected MyException (
SerializationInfo info,
StreamingContext context)
: base(info, context) { }
}
Change the FaultContract on IService.DoSomething to
typeof(MyException).
Change the throw clause in Service to
new FaultException<MyException>(new MyException(e.Message, e);
Change the catch clause in the client to
catch (FaultException<MyException> e)
When I execute this, a CommunicationException is caught on the client with the error:
System.ServiceModel.CommunicationException: There was an error reading from the pipe: The pipe has been ended. (109, 0x6d).
The MyException class is in a shared library available to both the client and server.
This question is very similar to this question, but that did not help me.
I resolved this by writing my own fault DataContract which contained a serialized list of StackFrames.
Apparently this MSDN article is not exactly accurate?
http://msdn.microsoft.com/en-us/library/ff649840.aspx
[DataContract]
public class MyFault
{
[DataMember]
public string Message { get; set; }
[DataMember]
public IList<SerializableMiniStackFrame> StackTrace { get; set; }
public static MyFault CreateFault(Exception e)
{
MyFault fault = new MyFault();
fault.Message = e.Message;
fault.InitTrace(e);
return fault;
}
/// <summary>
/// Initializes the stack trace based on when the inner exception was thrown.
/// </summary>
/// <param name="inner">The inner exception.</param>
private void InitTrace(Exception inner)
{
StackTrace trace = new StackTrace(inner, true);
InitTrace(trace);
}
/// <summary>
/// Initializes the internal serializable stack frames based on the given
/// stack trace.
/// </summary>
/// <param name="stackTrace">The stack trace.</param>
private void InitTrace(StackTrace stackTrace)
{
// Create a new list of serializable frames.
this.StackTrace = new List<SerializableMiniStackFrame>();
// Iterate over each frame in the stack trace.
foreach (StackFrame frame in stackTrace.GetFrames())
{
string type = "";
Type declaringType = frame.GetMethod().DeclaringType;
if (null != declaringType)
{
type = declaringType.FullName;
}
MethodBase method = frame.GetMethod();
string methodName = method.Name;
string parameters = string.Empty;
string delimiter = string.Empty;
foreach (ParameterInfo parameter in method.GetParameters())
{
parameters += string.Format("{0}{1} {2}", delimiter, parameter.ParameterType.Name, parameter.Name);
delimiter = ", ";
}
string file = Path.GetFileName(frame.GetFileName());
int line = frame.GetFileLineNumber();
// Create a serializable frame and add it to the list.
SerializableMiniStackFrame miniFrame = new SerializableMiniStackFrame(type, methodName, parameters, file, line);
this.StackTrace.Add(miniFrame);
}
}
}
/// <summary>
/// This class encapsulates basic stack frame information into a serializable
/// object.
/// </summary>
[DataContract]
public class SerializableMiniStackFrame
{
public SerializableMiniStackFrame() { }
public SerializableMiniStackFrame(string type, string method, string parameters, string file, int line)
{
this.Type = type;
this.Method = method;
this.Parameters = parameters;
this.File = file;
this.Line = line;
}
[DataMember]
public string Type { get; set; }
[DataMember]
public string Method { get; set; }
[DataMember]
public string Parameters { get; set; }
[DataMember]
public string File { get; set; }
[DataMember]
public int Line { get; set; }
}