Custom View folder in NancyFx - nancy

I want to use different folders other than Views with NancyFx. I've created a custom bootstrapper and it looks like:
using Nancy;
namespace MyBootstrapperTest
{
public class CustomBootstrapper : DefaultNancyBootstrapper
{
protected override void ConfigureConventions(Nancy.Conventions.NancyConventions nancyConventions)
{
nancyConventions.ViewLocationConventions.Add((viewName, model, context)) => string.Concat("html/", viewName));
}
}
}
But Visual Studio is telling me that the overloaded function, ViewLocationConventions.Add, has invalid arguments. Am I missing something? I'm pretty new to Nancy, using Nancy self-hosting at version 0.21.1.

You're not closing the parenthesis properly. Also it could be convenient to clear conventions first:
nancyConventions.ViewLocationConventions.Clear();
nancyConventions.ViewLocationConventions.Add((viewName, model, context) =>
string.Concat("html/", viewName));

Related

Error when using a custom view location convention with Nancy's ConfigurableBootstrapper

I am using a subclass of ConfigurableBootstrapper to test my Nancy modules. This is a workaround to get the ConfigurableBootstrapper to pick up the custom view location convention I use in the 'real' bootstrapper:
public class ConfigurableBootstrapperWithCustomConvention : ConfigurableBootstrapper
{
public ConfigurableBootstrapperWithCustomConvention(Action<ConfigurableBootstrapperConfigurator> configuration)
: base(configuration)
{
}
protected override void ConfigureConventions(NancyConventions nancyConventions)
{
nancyConventions.ViewLocationConventions.Add((viewName, model, context) =>
string.Concat(context.ModuleName, "/Views/", viewName));
base.ConfigureConventions(nancyConventions);
}
}
In my tests I first set the root path to that of my nancy project using the FakeRootPathProvider. This contains the necessary folder structure ("/Home/Views/Index.cshtml") for the view used in HomeModule to be located using this custom convention. The (simplified) test code:
[Test]
public void when_the_default_page_is_loaded_it_should_show_links_to_submit_form()
{
FakeRootPathProvider.RootPath = "../../../MyApp.Web";
var bootstrapper = new ConfigurableBootstrapperWithCustomConvention(with =>
{
with.RootPathProvider(new FakeRootPathProvider());
with.ViewEngine<RazorViewEngine>();
with.Module<HomeModule>();
});
var browser = new Browser(bootstrapper);
var response = browser.Get("/");
Assert.That(response.Body.AsString(), Is.StringContaining("<a href=\"SubmitSelf\">"));
}
When I run this test I get the following exception (at the call to response.Body):
System.ArgumentNullException : Value cannot be null.
Parameter name: httpContext
at System.Web.HttpContextWrapper..ctor(HttpContext httpContext)
at System.Web.Optimization.Styles.RenderFormat(String tagFormat, String[] paths)
at RazorOutput.RazorView.Execute()
at Nancy.ViewEngines.Razor.NancyRazorViewBase`1.ExecuteView(String body, IDictionary`2 sectionContents)
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid3<T0,T1,T2>(CallSite site, T0 arg0, T1 arg1, T2 arg2)
at Nancy.ViewEngines.Razor.RazorViewEngine.<>c__DisplayClass27.<RenderView>b__26(Stream stream)
at Nancy.Testing.BrowserResponse.get_Body()
at MyApp.Tests.Integration.Web.Home.HomeModuleTests.when_the_default_page_is_loaded_it_should_show_links_to_submit_form() in HomeModuleTests.cs: line 44
If I set the Fake root path to be "../../../MyApp.Web/Home/Views" instead, the test runs OK. (It appears that the custom view location convention is being ignored when testing using Nancy's "Browser" class).
Is there some issue with setting a NancyConvention in this way?
If so is there a different way to set a view location convention with ConfigurableBootstrapper?

Ninject does not resolve dependency correctly in silverlight project

I have a silverlight 4 project with mvvmlight and ninject 3.x.
I've setup the container like this
kernel = new StandardKernel(new ViewModelModule(), new ClientSessionModule());
And the modules like this
public class ViewModelModule : NinjectModule
{
public override void Load()
{
((StandardKernel)Kernel)
.Bind(scanner => scanner.FromThisAssembly()
.Select(x => x.IsSubclassOf(typeof(ViewModelBase)))
.BindDefaultInterface());
}
}
and
public class ClientSessionModule : NinjectModule
{
public override void Load()
{
Kernel.Bind<IClientContext>().To<ClientContext>().InSingletonScope();
}
}
Now the problem is the latter one. At one point in the application this dependency is resolved explictly and updated like this:
var context = App.Ioc.Get<IClientContext>();
context.Username = "just a sample name";
Now when a ViewModel is loaded it get the IClientContext injected like
public MainViewModel(IClientContext clientContext)
The problem is that the instance does not have the name set earlier.
But if I inside the same ViewModel resolves explictly again I get the expected instance with the name set.
What am I missing since the sigleton does not get injected as I expected it to be automatically?
Just found a duplicate kernel in my solution. And that explains why I was not able so resolve as expected as I had 2 kernels running

TooManyRowsAffectedException with encrypted triggers

I'm using nHibernate to update 2 columns in a table that has 3 encrypted triggers on it. The triggers are not owned by me and I can not make changes to them, so unfortunately I can't SET NOCOUNT ON inside of them.
Is there another way to get around the TooManyRowsAffectedException that is thrown on commit?
Update 1
So far only way I've gotten around the issue is to step around the .Save routine with
var query = session.CreateSQLQuery("update Orders set Notes = :Notes, Status = :Status where OrderId = :Order");
query.SetString("Notes", orderHeader.Notes);
query.SetString("Status", orderHeader.OrderStatus);
query.SetInt32("Order", orderHeader.OrderHeaderId);
query.ExecuteUpdate();
It feels dirty and is not easily to extend, but it doesn't crater.
We had the same problem with a 3rd party Sybase database. Fortunately, after some digging into the NHibernate code and brief discussion with the developers, it seems that there is a straightforward solution that doesn't require changes to NHibernate. The solution is given by Fabio Maulo in this thread in the NHibernate developer group.
To implement this for Sybase we created our own implementation of IBatcherFactory, inherited from NonBatchingBatcher and overrode the AddToBatch() method to remove the call to VerifyOutcomeNonBatched() on the provided IExpectation object:
public class NonVerifyingBatcherFactory : IBatcherFactory
{
public virtual IBatcher CreateBatcher(ConnectionManager connectionManager, IInterceptor interceptor)
{
return new NonBatchingBatcherWithoutVerification(connectionManager, interceptor);
}
}
public class NonBatchingBatcherWithoutVerification : NonBatchingBatcher
{
public NonBatchingBatcherWithoutVerification(ConnectionManager connectionManager, IInterceptor interceptor) : base(connectionManager, interceptor)
{}
public override void AddToBatch(IExpectation expectation)
{
IDbCommand cmd = CurrentCommand;
ExecuteNonQuery(cmd);
// Removed the following line
//expectation.VerifyOutcomeNonBatched(rowCount, cmd);
}
}
To do the same for SQL Server you would need to inherit from SqlClientBatchingBatcher, override DoExectuteBatch() and remove the call to VerifyOutcomeBatched() from the Expectations object:
public class NonBatchingBatcherWithoutVerification : SqlClientBatchingBatcher
{
public NonBatchingBatcherWithoutVerification(ConnectionManager connectionManager, IInterceptor interceptor) : base(connectionManager, interceptor)
{}
protected override void DoExecuteBatch(IDbCommand ps)
{
log.DebugFormat("Executing batch");
CheckReaders();
Prepare(currentBatch.BatchCommand);
if (Factory.Settings.SqlStatementLogger.IsDebugEnabled)
{
Factory.Settings.SqlStatementLogger.LogBatchCommand(currentBatchCommandsLog.ToString());
currentBatchCommandsLog = new StringBuilder().AppendLine("Batch commands:");
}
int rowsAffected = currentBatch.ExecuteNonQuery();
// Removed the following line
//Expectations.VerifyOutcomeBatched(totalExpectedRowsAffected, rowsAffected);
currentBatch.Dispose();
totalExpectedRowsAffected = 0;
currentBatch = new SqlClientSqlCommandSet();
}
}
Now you need to inject your new classes into NHibernate. There are at two ways to do this that I am aware of:
Provide the name of your IBatcherFactory implementation in the adonet.factory_class configuration property
Create a custom driver that implements the IEmbeddedBatcherFactoryProvider interface
Given that we already had a custom driver in our project to work around Sybase 12 ANSI string problems it was a straightforward change to implement the interface as follows:
public class DriverWithCustomBatcherFactory : SybaseAdoNet12ClientDriver, IEmbeddedBatcherFactoryProvider
{
public Type BatcherFactoryClass
{
get { return typeof(NonVerifyingBatcherFactory); }
}
//...other driver code for our project...
}
The driver can be configured by providing the driver name using the connection.driver_class configuration property. We wanted to use Fluent NHibernate and it can be done using Fluent as follows:
public class SybaseConfiguration : PersistenceConfiguration<SybaseConfiguration, SybaseConnectionStringBuilder>
{
SybaseConfiguration()
{
Driver<DriverWithCustomBatcherFactory>();
AdoNetBatchSize(1); // This is required to use our new batcher
}
/// <summary>
/// The dialect to use
/// </summary>
public static SybaseConfiguration SybaseDialect
{
get
{
return new SybaseConfiguration()
.Dialect<SybaseAdoNet12Dialect>();
}
}
}
and when creating the session factory we use this new class as follows:
var sf = Fluently.Configure()
.Database(SybaseConfiguration.SybaseDialect.ConnectionString(_connectionString))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<MyEntity>())
.BuildSessionFactory();
Finally you need to set the adonet.batch_size property to 1 to ensure that your new batcher class is used. In Fluent NHibernate this is done using the AdoNetBatchSize() method in a class that inherits from PersistenceConfiguration (see the SybaseConfiguration class constructor above for an example of this).
er... you might be able to decrypt them...
Edit: if you can't change code, decrypt, or disable then you have no code options on the SQL Server side.
However, You could try "disallow results from triggers Option" which is OK for SQL 2005 and SQL 2008 but will be removed in later versions. I don't know if it suppresses rowcount messages though.
Setting the "Disallow Results from Triggers" option to 1 worked for us (the default is 0).
Note that this option will not be available in a future releases of Microsoft SQL Server, but after it is no longer available it will behave as if it was set to 1. So setting this to 1 now fixes the problem and also give you the same behavior as will be in future releases.

Visual Studio 2008 Winform designer fails to load Form which inherits from generic class

i have a winforms project, and i created a class on assembly A that inherits from System.Windows.Forms.Form to serve as a base class for various forms on my project, the base class is something like:
public partial class DataForm<T> : Form where T : class
{
T currentRecord;
protected T CurrentRecord
{
get
{
return currentRecord;
}
set
{
currentRecord = value;
CurrentRecordChanged();
}
}
}
Now, when i create a form on assembly B that inherits from my DataForm the designer won't load, but if i compile it the app runs fine.
The form looks like:
public partial class SomeTableWindow : DataForm<SomeTable>
{
public SomeTableWindow ()
{
InitializeComponent();
}
}
The error I'm getting is:
The designer could not be shown for this file because none of the classes within it can be designed.
The designer inspected the following classes in the file: CultivosWindow --- The base
class 'TripleH.Erp.Controls.DataForm' could not be loaded. Ensure the assembly has
been referenced and that all projects have been built.
Instances of this error (1)
1. Hide Call Stack
at System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.EnsureDocument(IDesignerSerializationManager manager)
at System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager manager)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager serializationManager)
at System.ComponentModel.Design.Serialization.BasicDesignerLoader.BeginLoad(IDesignerLoaderHost host)
Is this a bug on the designer?, Am I doing something wrong? Is there some workaround this?
Thank you for your help
It's a known limitation. Basically you can work around this by declaring another class that inherits from the generic class.
For instance:
class Generic<T> : UserControl
{
}
then
class GenericInt : Generic<int> { }
then use GenericInt instead of Generic. SUcks I know.

Silverlight: Cannot use reflection to GetValue of a field across XAPs?

I have a Silverlight application which has two different XAPs - an InitialXAP which is loaded statically by the HTML page and a DynamicXAP which is loaded from code within the initial XAP. The DynamicXAP is loaded with code similar to this:
var asm = LoadAssemblyFromXap(stream, "DLLName");
// LoadAssemblyFromXAP will load the DynamicXAP as a file stream,
// unpack it and load DLLName as a dll.
var controllerType = asm.GetType("ClassNameToInstantiate_InsideAsm");
var constructor = controllerType.GetConstructor(Type.EmptyTypes);
return constructor.Invoke(null);
I have a class which uses reflection (specifically FieldInfo.GetValue) to do data binding. This class is defined in the InitialXAP. If I try to use this class in the DynamicXAP, I get an error:
Message: Unhandled Error in Silverlight Application System.FieldAccessException: Class.In.DynamicXAP.Which.Uses.The.Reflection.Class.In.InitialXAP
at System.Reflection.RtFieldInfo.PerformVisibilityCheckOnField(IntPtr field, Object target, IntPtr declaringType, FieldAttributes attr, UInt32 invocationFlags)
at System.Reflection.RtFieldInfo.InternalGetValue(Object obj, Boolean doVisibilityCheck, Boolean doCheckConsistency)
at System.Reflection.RtFieldInfo.InternalGetValue(Object obj, Boolean doVisibilityCheck)
at System.Reflection.RtFieldInfo.GetValue(Object obj)
I can get around this error by creating a subclass of the class using reflection and overriding the method using reflection like so:
public class InitialXAP.ClassUsingReflection {
public virtual object GetValue()
{
return fieldInfo.GetValue(parent);
}
}
public class ClassUsingReflection : InitialXAP.ClassUsingReflection {
public override object GetValue()
{
return fieldInfo.GetValue(parent);
}
}
But I would prefer to avoid this duplication by allowing reflection from the InitialXAP in the DynamicXAP. Any ideas on what I can do?
Although there is a learning curve, I would look at Silverlight MEF or Prism (both are together at last in the latest Prism 4 Beta). They both support dynamic loading of modules and enforce good patterns for reuse and separate/team development.
InitialXAP.ClassUsingReflection...
Note the duplicate isn't part of the inital xap namespace (ClassUsingReflection), and may be imported.
Notice GetVisible - as in not visible to Dynamic xap...
Just leave the duplicate (take away base class obviously) and try.

Resources