Query Orchard CMS from IShapeFactoryEvents - asp.net-mvc

I am trying to insert shapes into my layout from my module once it has been enabled. I figured IShapeFactoryEvents would be perfect for this, but querying the CMS from here gives me a "TransactionScope nested incorrectly exception" if this occurs during a POST. Wondering if anyone had any words of wisdom for me again? See my code snippet below.
public void Created(ShapeCreatedContext context)
{
if (context.ShapeType == "Layout")
{
if (!AdminFilter.IsApplied(_services.WorkContext.HttpContext.Request.RequestContext))
{
var route = RouteTable.Routes.GetRouteData(_services.WorkContext.HttpContext);
object location;
if (route.Values.TryGetValue("location", out location))
{
var region = _services.ContentManager.Query("Region")
.Join<RoutePartRecord>()
.Where(x => x.Slug == (string)location)
.Slice(1).FirstOrDefault();
context.Shape.Header.Add(context.New.CurrentRegion(Title: region.As<RoutePart>().Title), "10");
}
context.Shape.Navigation.Add(context.New.RegionSelector(Regions: _services.ContentManager.Query(VersionOptions.Published, "Region").List()), "11");
}
}
}
Once again, thanks in advance. You guys are awesome.

See the blog post I did on this very topic here: http://chrisbower.com/2011/02/15/orchard-shape-wizardry/
From the blog post:
"One thing I need to note, and this took me an entire day to discover, is that you can't just inject your data service into your IShapeTableProvider implementation. If you do, it'll try to use a transaction out of scope and that will cause you all kinds of problems. After tearing my hair out for hours on end, I finally discovered what the Orchard team is doing inside of the CoreShapes class: The trick to resolve a service dependency within the function itself by using a property that loads the service per-request."
Try using your service like this instead:
private IOrchardServices Services
{
get
{
return _workContextAccessor.GetContext(_httpContextAccessor.Current()).Resolve<IOrchardServices>();
}
}

Related

Is it possible to see what's registered with OWIN's IAppBuilder?

I have a solution which makes use of many class libraries (optional plugins). It is actually very similar in design to nopCommerce. Anyway, I have the following interface:
public interface IOwinStartupConfiguration
{
void Configuration(IAppBuilder app);
}
Obviously what happens is that in my Startup class in the web project, I get a list of all registered IOwinStartupConfiguration instances in all plugins and then proceed to iterate over each one.
So far I only have one plugin using this, but that may change later. The thing I'm worried about is the possibility of more than 1 plugin calling something like:
app.MapSignalR();
Acccording to this page:
http://www.asp.net/signalr/overview/testing-and-debugging/troubleshooting
doing so would cause an error like
"A route named 'signalr.hubs' is already in the route collection"
Is it possible to see what's in the OWIN pipeline?
Ideally I would like to do something like this:
if (!app.IsSignalRMapped)
{
app.MapSignalR();
}
or
if (!app.HasMappedService("SignalR"))
{
app.MapSignalR();
}
Obviously I cannot find any such thing on the IAppBuilder interface. So what can I do in this situation?
I just stumbled upon MapWhen(), but it seemed a bit pointless. I was going to try something like this:
app.MapWhen(x => !existingConfigurations.Contains("SignalR"), x => app.MapSignalR());
where existingConfigurations is a new ICollection<string> passed in the modified method:
void Configuration(IAppBuilder app, ICollection<string> existingConfigurations)
However, I found it made more sense to simply do this:
if (!existingConfigurations.Contains("SignalR"))
{
app.MapSignalR();
existingConfigurations.Add("SignalR");
}
It's not a perfect solution, since someone could misspell "SignalR", for example. But since there's no IsSignalRMapped() method, it will have to suffice.
I haven't tried this but this might work:
var hub = GlobalHost.ConnectionManager.GetHubContext<MySignalRHub>();
if (hub == null)
{
app.MapSignalR();
}

ModelState.IsValid is false - But Which One - Easy Way

In ASP.NET MVC, when we call a post action with some data, we check ModelState and in case some validation error, it would be falst. For a big Enter User Information form, it is annoying to expand each Value and look at the count to see which Key (9 in attached example image) has validation error. Wondering if someone knows an easy way to figure out which element is causing validation error.
In VS2015+, you can use LINQ in the Immediate Window, which means you can just run the following:
ModelState.SelectMany(
x => x.Value.Errors,
(state, error) => $"{state.Key}: {error.ErrorMessage}"
)
I propose to write a method:
namespace System.Web
{
using Mvc;
public static class ModelStateExtensions
{
public static Tuple<string, string> GetFirstError(this ModelStateDictionary modelState)
{
if (modelState.IsValid)
{
return null;
}
foreach (var key in modelState.Keys)
{
if (modelState[key].Errors.Count != 0)
{
return new Tuple<string, string>(key, modelState[key].Errors[0].ErrorMessage);
}
}
return null;
}
}
}
Then during debugging open Immediate Window and enter:
ModelState.GetFirstError()
Sounds like you're looking for debugger enhancements. I recently came across this product in the visual studio gallery.
http://visualstudiogallery.msdn.microsoft.com/16acdc63-c4f1-43a7-866a-67ff7022a0ac
I have no affiliation with them, and haven't used it. It's also a trial version and have no idea how much it costs for the full thing.
If you're more focused on the debugger side of things, have a go with the trial copy of OzCode. It enhances the Visual Studio IDE by replacing the usual debugging tooltip with it's own, more powerful, debugging tooltip. It's hard to epxlain with words, check out their website, they have a gallery of features on there.
I've been playing around with the beta for a few weeks, and it's proved a very valuable tool. You can query against data in the debugger using OzCode. For example, you could query items in the ModelState by filtering against the Values collection.

May a scenario not have a When in BDD?

I'm currently learning/testing BDD using SpecFlow, and it works great!
Before I choose to ask my question, I have read this one, and I felt like I had to ask my question despite the fact that the same problem is addressed, because of the Exception scenario which is not mentioned.
I'm actually testing this scenario:
Scenario: I should get an error whenever I try to remove an item from an empty stack
Given I have an empty stack
When I pop from it
Then I should get an error
public class StackBehaviour {
public void GivenIHaveAnEmptyStack() { stack = new CustomStack<string>(); }
// This will throw whenever called!
// So the Then method will never be run!
// I feel like I should just put a comment which says why it's empty,
// allowing a fellow programmer to understand the exact intention.
public void WhenIPopFromIt() { stack.Pop(); }
// It is here that it verifies whether the CustomStack meets the expected behaviour.
public void ThenIShouldGetAnError() {
Assert.Throws<IndexOutOfRangeException>(delegate {
stack.Pop();
});
}
private CustomStack<string> stack;
}
public class CustomStack<T> {
public T Pop() {
if (stack.Count == 0)
throw new IndexOutOfRangeException("Cannot pop from an empty stack!");
T item = stack[stack.Count-1];
stack.RemoveAt(stack.Count-1);
return item;
}
private ArrayList stack = new ArrayList();
}
I think that leaving a comment in the When method is correct, so that the business requirement doesn't lack any information, and on the code behind, I put it clear what my intention is exactly by commenting.
What do you think? Any other ideas why I shouldn't make it?
There is another trick that you can use where the bindings help make the feature's meaning a little clearer. In this case, let's start at the end.
Then I should get an error
Your problem is a basically here, you know want an error, but you don't know how to get it. In fact you've already missed it, the error has already occurred in the When step, and in your code example, you moved the action into the then step just so you could get the error.
But what if keep the when performing the action amd re-express our then to reflect what really happens
Then I should have had an error
Seems a trivial change but now our feature reflects that the error should have been associated with the When step and we are simply evaluating it later, and that is something we can code. We just need something to remember the error in the when and deliver it to the then.
private Exception errorFromWhen = null;
public void WhenIPopFromIt()
{
try
{
stack.Pop();
}
catch(Exception ex)
{
errorFromWhen = ex;
}
}
public void ThenIShouldGetAnError()
{
errorFromWhen.ShouldNotBeNull();
errorFromWhen.ShouldBe<IndexOutOfRangeException>();
}
SpecFlow has absolutely no problems with this, in fact due to its mini Dependency injection system, you can even pass this state between binding classes if necessary.
May a scenario not have a When in BDD?
In Specflow, neither given, when or then are mandatory.
However in your example, I don't believe this is a good use of Specflow and BDD. In this answer here Marcus states:
"BDD is about ensuring that we're building the right thing, TDD is about ensuring that we're building it right."
In your example the scope of what is being tested i.e. the CustomStack, should be tested via TDD. It is the end solution that makes use of the CustomStack should be tested via BDD (and hence SpecFlow) e.g. if this CustomStack was being exercised via a certain action on a website.
This answer is also pertinent to your question.

Role-based navigation display in MVC4 Bootstrap Sample

How are you supposed to conditionally display menu items based on roles in the Bootstrap Sample project? I was thinking of doing the following
Implement INavigatonRouteFilter - really just implementing the shouldRemove(Route navigationRoutes) method - by getting the default controller/action for the route and seeing if the user is authorized
Call NavigationRoutes.Filters.Add(myAuthorizationFilter) after configuring the NavigationRoutes in App_Start
There are two problems I see with this approach:
I don't actually know how to do the first step unless I add in a bunch of conditional statements to check for Controller's name explicitly
This seems like it could make NavigationRoutes.Filters very hard to deal with once there are a lot of filters or a desire for more modularity later on
I don't know that I've explained the problem clearly enough, but basically I want to use what is provided in the Bootstrap sample to implement authorization-based navigation menu display if at all possible. Using INavigationRouteFilter just seemed like the most natural way to do so.
For those looking for an answer or at least a quick fix.
Here's what I've come up with after 5 minutes and I most certainly haven't though about any side effects this may have.
routes.MapNavigationRoute<HomeController>("Index", c => c.Index())
.FilterRoute(() => !WebSecurity.IsAuthenticated);
You can either do all your filtering in your call to FilterRoute() or you can add more extension methods to save you some characters.
I'm thinking of .RequireRole("Adiministrators"); that calls WebSecurity.RequireRoles() in turn (or HttpContext.Current.User.IsInRole()) etc.
public static NavigationRouteBuilder FilterRoute(this NavigationRouteBuilder builder, Func<bool> func)
{
var currentRoute = builder._parent;
NavigationRoutes.Filters.Add(new BootstrapAuthorizationFilter(builder, x =>
{
if (x == currentRoute)
return func();
else
return false;
}));
return builder;
}
and BootstrapAuthorizationFilter is just a class implementing INavigationRouteFilter that calls func() in its ShouldRemove() method
public class BootstrapAuthorizationFilter : INavigationRouteFilter
{
private NavigationRouteBuilder builder;
private Func<NamedRoute, bool> func;
public BootstrapAuthorizationFilter(NavigationRouteBuilder builder, Func<NamedRoute, bool> func)
{
this.builder = builder;
this.func = func;
}
public bool ShouldRemove(Route navigationRoutes)
{
if (navigationRoutes is NamedRoute)
return func(navigationRoutes as NamedRoute);
return false;
}
}
Clearly nothing fancy and I'm not sure if I'd use it in production.
But I think is simple enough and works (for the cases I tested).
Having said that, I hope the new routing functionality is going to be released soon :)

How to get TotalRows Count in Breezejs, so that I can do paging

I am using Breezejs for client JavaScript. I am not sure how to get the Total count of query when using Breezejs (server side using IQueryable) that has filters (where clause) applied.
As of v 0.75.1 we have added a new 'inlineCount' method to the EntityQuery. Please see the breeze API docs for more details. Hopefully, this will provide what you need.
We made a little change to Ward's solution, because Enumerable.Count loads all records from db, not only count (we realized this after watching sql profiler).
First we create a wrapper for IQueryable.Count extension method (because we cannot call an extension method via reflection).
public static class QueryWrapper {
public static int Count<T>(IQueryable<T> query) where T: class {
return query.Count();
}
}
and we changed
if (actionExecutedContext.Request.RequestUri.Query.Contains("$inlinecount")) {
if (dQuery is IQueryable) {
inlineCount = Enumerable.Count(dQuery);
}
}
with this code,
if (actionExecutedContext.Request.RequestUri.Query.Contains("$inlinecount")) {
if (dQuery is IQueryable) {
var method = typeof(QueryWrapper).GetMethod("Count");
var genericMethod = method.MakeGenericMethod(elementType);
inlineCount = (int)genericMethod.Invoke(null, new object[] { dQuery });
}
}
after this change, Entity Framework gets only count, not all records.
Hope this helps.
Have a nice day.
Support $inlinecount in queries currently is under review - please vote for it.
UPDATE: $inlineCount is in Breeze as of v.0.75.1, rendering this answer obsolete.
Accordingly, I have deleted my answer which described a workaround (a workaround improved by Umut Özel in his answer here). The new feature was driven by this S.O. question and all of your contributions. Thank you.

Resources