This is a strange bug. I have a controller derived from Csla.Web.Mvc.Controller. When I attempt to unit test it, checking to see if it retrieves the correct view, I get the following error when calling, "return View()";
Attempt by method 'MvcPoc.UI.WebApplication.Controllers.MyController.List()' to access method 'System.Web.Mvc.Controller.View()' failed.
On closer inspection this line does not seem to work;
ViewData.Model = MyItemList.Get(); Model remains null (and yes 'Get' is returning a list not null). The strange thing is, the model is null in the debugger but if I add this line,
var isnull = (ViewData.Model == null); isnull remains false!? There must be some quantum computing going on as the Model seems to be both null and not null at the same time. If I change the base class to the System.Web.Mvc.Controller this problem goes away and the test passes.
This led me to believe that the problem may have to do with reflection in the system controller class. So I derived my own controller from it and tried that. No problem.
I then built my controllerbase to look the same as the one in csla. Again, no problem
I then derived my base class from csla controller and got the access error again.
So then I thought this was a scope thing, so I moved my controllerBase to an external assembly, derived from system controller and still no problem. The problem returned when I derived it from the csla controller.
The only way to replicate this error is to use the csla controller. I'm at an impasse here. This problem is easy to test;
I am running into the same issue
I have done the same tests and came to the same set of results
Has anyone else run into this?
I've looked through the Latest EBook and accompaning code hoping to find a sample or help in testing and was surprised to see no tests for the MVC Project
Hopefully someone else has come across this and can point to a solution to this problem
Can you post a sample project with unit test project that fails?
Does your MVC app and unit test projects also include reference to Csla.Web?
I created the same project on my machine and the UnitTests run just fine.
Csla.Web.Mvc.Conttroller inherits from System.Web.Mvc.Controller and only adds 2 new methods:
Hi
Thanks for the quick response
To See the Same Results
Create a Sample Razor Application and include the Unit Tests
Compile and Run the default Controller Tests (About and Home)
All works
Change to inherit from CSLA Controller
Run the Test -
Both Tests Fail
Any Help would be greatly appreciated
HI
Yes I do have the References to CSLA, CSLA.WEB and CSLA.MVC
I did exactly that - and changed both HomeController and AboutController to inherit from Csla.Web.Mvc.Controller.
And all unit tests run just fine. I am using the latest CSLA version from svn trunk.
Odds are that the unit test project isn't configured correctly in some way.
If the failure is on your .Get() factory call, then you must remember to configure your unit test project so the data portal works, and so your data access code works.
I usually configure the data portal to be local and to use a mock DAL. Sometimes I'll use a remote data portal with a mock DAL.
But it is a pretty good bet that the problem isn't in the controller, but rather is deeper - like when the data portal tries to talk to the app server.
OR, the second most likely issue tends to revolve around the use of a custom principal. Unit test frameworks sometimes make this difficult, because the same thread moves between different AppDomains (the test runner, and the test itself). Also, tests that rely on authz rules need some pre-existing authn condition to be set in the test, or better yet in a test initializer.
Thanks for the Response
I have other tests that are exercising the DAL and In those cases there is a separate Mock DAL and the tests work correctly
But It does seem to be an access issue as the Exact Error is
Attempt by method 'Ecord.Razor.Controllers.HomeController.Index()' to access method 'System.Web.Mvc.Controller.View()' failed.
and the troubleshooting tip is
A MethodAccessException exception is thrown when there is an invalid attempt to access a private or protected method inside a class.
In this case there is no Data Access or Security Checking
The Controllers simply serve up the default views so No DAL and No real use of CSLA
So Strange
Hi
Some Further Information
I implemented a MVCFakes in hopes of isolating the root cause
I was able to get the Following error when creating a Fake Controller Context
Unable to cast object of type 'Ecord.Razor.Controllers.HomeController' to type 'System.Web.Mvc.ControllerBase'
Again, this error only happens when I am inheriting CSLA.Web.MVC.Controller
Hi,
Have you checked to verify that Csla.Web.Mvc and your project references the same version of System.Web.Mvc?
Hi
Thanks again for the Quick reply
In order to confirm I have recompiled the CSLA source and updated the references
They are the Same
Thanks angain for any help
Hi,
I had the same problem in my project. I simply reimplemented the Csla.Web.Mvc.Controller class in my project and everything is working fine. I'm not sure of the exact cause but it's a nice workaround...
Guillaume,
Hi Guillaume
Thanks for your response
Please explain what you meant by implementing it in your own project. Does this mean you copied the files into your MVC program and did not use the CSLA DLL?
I look forward to your response
Have a GREAT Day
Hi Bill,
Here's the code I added into my project :
using System;
using Csla;
using Csla.Core;
using Csla.Server;
using Csla.Web.Mvc;
namespace MyProjectNamespace
{
/// <summary>
/// Overrides the CSLA controller to handle error.
/// </summary>
public class MyCSLAController : System.Web.Mvc.Controller
{
/// <summary>
/// Performs a Save() operation on an
/// editable business object, with appropriate
/// validation and exception handling.
/// </summary>
/// <typeparam name="T">Type of business object.</typeparam>
/// <param name="item">The business object to insert.</param>
/// <param name="forceUpdate">true to force Save() to be an update.</param>
/// <returns>true the Save() succeeds, false if not.</returns>
protected internal virtual bool SaveObject<T>(T item, bool forceUpdate)
where T : class, ISavable
{
return this.SaveObject<T>(
item,
delegate(T i) { this.UpdateModel<T>(i); },
forceUpdate);
}
/// <summary>
/// Performs a Save() operation on an
/// editable business object, with appropriate
/// validation and exception handling.
/// </summary>
/// <typeparam name="T">Type of business object.</typeparam>
/// <param name="item">The business object to insert.</param>
/// <param name="updateModel">Delegate that invokes the UpdateModel() method.</param>
/// <param name="forceUpdate">true to force Save() to be an update.</param>
/// <returns>true the Save() succeeds, false if not.</returns>
protected bool SaveObject<T>(T item, Action<T> updateModel, bool forceUpdate)
where T : class, ISavable
{
bool result;
try
{
this.ViewData.Model = item;
if (updateModel != null)
{
updateModel(item);
}
this.ViewData.Model = item.Save(forceUpdate);
result = true;
}
catch (Csla.DataPortalException ex)
{
if (ex.BusinessException != null)
{
this.ModelState.AddModelError(string.Empty, ex.BusinessException.Message);
}
else
{
this.ModelState.AddModelError(string.Empty, ex.Message);
}
result = false;
}
catch (Exception ex)
{
this.ModelState.AddModelError(string.Empty, ex.Message);
result = false;
}
return result;
}
/// <summary>
/// Loads a property's managed field with the
/// supplied value calling PropertyHasChanged
/// if the value does change.
/// </summary>
/// <typeparam name="T">
/// Type of the property.
/// </typeparam>
/// <param name="target">
/// Object on which to call the method.
/// </param>
/// <param name="propertyInfo">
/// PropertyInfo object containing property metadata.</param>
/// <param name="newValue">
/// The new value for the property.</param>
/// <remarks>
/// No authorization checks occur when this method is called,
/// and no PropertyChanging or PropertyChanged events are raised.
/// Loading values does not cause validation rules to be
/// invoked.
/// </remarks>
protected void LoadProperty<T>(object target, PropertyInfo<T> propertyInfo, T newValue)
{
new ObjectManager().LoadProperty(target, propertyInfo, newValue);
}
/// <summary>
/// Manage the CSLA objects
/// </summary>
private class ObjectManager : Csla.Server.ObjectFactory
{
/// <summary>
/// Load the property
/// </summary>
/// <typeparam name="P">the generic type</typeparam>
/// <param name="obj">the object</param>
/// <param name="propertyInfo">the CSLA property</param>
/// <param name="newValue">the new value</param>
public new void LoadProperty<P>(object obj, PropertyInfo<P> propertyInfo, P newValue)
{
this.LoadProperty(obj, propertyInfo, newValue);
}
}
}
}
Copyright (c) Marimer LLC