In earlier blogs (Part 1 and Part 2 of this series) I described how I have developed a Framework that allows developers to create DotNetNuke (DNN) modules using the new ASP.NET MVC Framework.  In this blog I will describe the new base class which is used to enable this ability - MvcModuleApplication.

Prior to DotNetNuke 5.0, all module controls had to be ASP.NET User Controls that inherited from PortalModuleBase – a base class in the DotNetNuke Web Application Framework that provided the context necessary for DotNetNuke’s Module Injection logic to load and inject the module control in the page. (Since about DNN 4.4 a module control was not required to be an ascx file – it could be a compiled server control, but it still had to inherit from PortalModuleBase and thus ultimately from UserControl).

IModuleControl

In DNN 5.0 an interface was introduced – IModuleControl – and the Module Injection logic was refactored to require the control to implement IModuleControl, rather than inherit from PortalModuleBase.  PortalModuleBase itself was refactored to implement this interface so no existing modules were broken.

Creation of this interface means that it is no longer necessary to inherit from UserControl – although we are still required to ultimately inherit from the base class Control.

MvcModuleApplication

As demonstrated in Part 1 of this series, MVC Modules are required to include a class that inherits from MvcModuleApplication.

Listing 1 – The MVC_TestApplication class
   1:  public class MVC_TestApplication : MvcModuleApplication
   2:  {
   3:      protected override string FolderPath
   4:      {
   5:          get { return "MVC_Test"; }
   6:      }
   7:   
   8:      protected override void Init()
   9:      {
  10:          base.Init();
  11:          RegisterRoutes(Routes);
  12:      }
  13:   
  14:      private static void RegisterRoutes(RouteCollection routes)
  15:      {
  16:          routes.RegisterDefaultRoute("MVC_Test.Controllers");
  17:      }
  18:  }

Listing 1 shows the class we added to the Test MVC module we created in the first part of this series.  As discussed above, DotNetNuke Modules need to implement the interface IModuleControl and inherit from Control (this is necessary as the framework either needs to load a UserControl (ie ascx) or instantiate a Control and add it to the Controls collection of the Container.  This is demonstrated in Listing 2, which shows the new base class – MvcModuleApplication - before we add any  MVC Framework enabling code.

Listing 2 – The MvcModuleApplication class
   1:  namespace DotNetNuke.Web.Mvc
   2:  {
   3:      public abstract class MvcModuleApplication : Control, IModuleControl
   4:      {
   5:          #region IModuleControl Implementation
   6:   
   7:          public Control Control
   8:          {
   9:              get { throw new NotImplementedException(); }
  10:          }
  11:   
  12:          public string ControlPath
  13:          {
  14:              get { throw new NotImplementedException(); }
  15:          }
  16:   
  17:          public string ControlName
  18:          {
  19:              get { throw new NotImplementedException(); }
  20:          }
  21:   
  22:          public string LocalResourceFile
  23:          {
  24:              get { throw new NotImplementedException(); }
  25:              set { throw new NotImplementedException(); }
  26:          }
  27:   
  28:          public ModuleInstanceContext ModuleContext
  29:          {
  30:              get
  31:              {
  32:                  if (_moduleContext == null)
  33:                  {
  34:                      _moduleContext = new ModuleInstanceContext(this);
  35:                  }
  36:                  return _moduleContext;
  37:              }
  38:          }
  39:   
  40:          #endregion
  41:      }
  42:  }

Now that we have our base class, we can add the pieces to enable MVC modules.  In Part 2 of this series I described the MVC Pipeline.  We are going to plug in to this pipeline right at the beginning by implement logic similar to the ProcessRequest method of the MvcHandler. (So readers don’t have to refer back to the earlier blog, this method is shown in Listing 3).

Listing 3 - MvcHandler, ProcessRequest method
   1:  protected internal virtual void ProcessRequest(HttpContextBase httpContext) {
   2:      AddVersionHeader(httpContext);
   3:   
   4:      // Get the controller type
   5:      string controllerName = RequestContext.RouteData.GetRequiredString("controller");
   6:   
   7:      // Instantiate the controller and call Execute
   8:      IControllerFactory factory = ControllerBuilder.GetControllerFactory();
   9:      IController controller = factory.CreateController(RequestContext, controllerName);
  10:      if (controller == null) {
  11:          throw new InvalidOperationException(
  12:              String.Format(
  13:                  CultureInfo.CurrentUICulture,
  14:                  MvcResources.ControllerBuilder_FactoryReturnedNull,
  15:                  factory.GetType(),
  16:                  controllerName));
  17:      }
  18:      try {
  19:          controller.Execute(RequestContext);
  20:      }
  21:      finally {
  22:          factory.ReleaseController(controller);
  23:      }
  24:  }

As the MvcModuleApplication class inherits from Control it is part of the WebForms Page Life Cycle.  We will override the OnInit method which is our first opportunity to implement our own code (Listing 4).

Listing 4 – MvcModuleApplication, OnInit
   1:  protected override void OnInit(EventArgs e)
   2:  {
   3:      base.OnInit(e);
   4:   
   5:      //Wrap the http Context
   6:      HttpContextBase httpContext = new HttpContextWrapper(HttpContext.Current);
   7:   
   8:      // Setup the module's context
   9:      ModuleRequestContext moduleRequestContext = new ModuleRequestContext
  10:      {
  11:          ModuleContext = ModuleContext,
  12:          ModuleRoutingUrl = "", // for now we will pass in an empty string
  13:          HttpContext = httpContext
  14:      };
  15:   
  16:      _moduleResult = ExecuteRequest(moduleRequestContext);
  17:  }

In this method we first create an instance of HttpContextBase – from the HttpContext (line 6).  The MVC Framework uses this abstract base class to enable better testability, so we need to do the same. 

Next, we create a ModuleRequestContext object (lines 9-14).  This class is a helper class that enables us to pass around the ModuleContext (from IModuleControl) a RoutingUrl and the HttpContext to any method that needs this information. 

Finally we call the ExecuteRequest method, passing it this helper object and getting a ModuleRequestResult back (line 16).

Listing 5 – MvcModuleApplication, ExecuteRequest
   1:  public virtual ModuleRequestResult ExecuteRequest(ModuleRequestContext context) {
   2:      EnsureInitialized(context.HttpContext);
   3:   
   4:      // Create a rewritten HttpRequest (wrapped in an HttpContext) to provide to the 
   5:      //routing system
   6:      HttpContextBase rewrittenContext = new RewrittenHttpContext(context.HttpContext, 
   7:                                                  context.ModuleRoutingUrl);
   8:   
   9:      // Route the request
  10:      RouteData routeData = GetRouteData(rewrittenContext);
  11:   
  12:      // Setup request context
  13:      string controllerName = routeData.GetRequiredString("controller");
  14:      RequestContext requestContext = new RequestContext(context.HttpContext, routeData);
  15:   
  16:      // Construct the controller using the ControllerFactory
  17:      IControllerFactory factory = ControllerBuilder.GetControllerFactory();
  18:      IController controller = factory.CreateController(requestContext, controllerName);
  19:      try {
  20:          // DotNetNuke Mvc Modules must implement IModuleController (not just IController)
  21:          // Because we need to retrieve the ActionResult without executing it, IController
  22:          // won't cut it so attempt to adapt the Controller if it does not directly 
  23:          // implement IModuleController
  24:          IModuleController moduleController = controller as IModuleController;
  25:          if (moduleController == null)
  26:          {
  27:              moduleController = AdaptController(controller);
  28:          }
  29:          if (moduleController == null) {
  30:              throw new InvalidOperationException("Could not construct ModuleController");
  31:          }
  32:   
  33:          // Execute the controller and capture the result
  34:          moduleController.Execute(requestContext);
  35:          ActionResult result = moduleController.ResultOfLastExecute;
  36:   
  37:          // Return the final result
  38:          return new ModuleRequestResult {
  39:              ActionResult = result,
  40:              ControllerContext = moduleController.ControllerContext,
  41:              ModuleContext = context.ModuleContext
  42:          };
  43:      }
  44:      finally {
  45:          factory.ReleaseController(controller);
  46:      }
  47:  }

The ExecuteRequest method (Listing 5) is very similar to the ProcessRequest method of MvcHandler, and so it should be as we need to do the same things, construct a Controller class and execute the Controller so it can Invoke the appropriate action.  So lines 17 and 18 of Listing 5 are almost identical to lines 8 and 9 of Listing 3.

However there are a few differences.

  • At the beginning of the method we do some setup work that is handled by other classes in the ASP.NET MVC Pipeline (lines 2-10).
  • DotNetNuke MVC Modules must implement IModuleController (not just IController), so we attempt to cast the returner controller to IModuleController, and if that fails we attempt to adapt it (line 27)
  • After we call the Execute method of Controller we then use the IModuleController’s "ResultOfLastExecute property to trap the ActionResult, which is returnedd by the Controller’s “action” method (lines 34-35).
  • We generate a ModuleRequestResult to return to the caller code in OnInit (lines 38-42)

The important difference here is that unlike the main MVC Framework we need to trap the ActionResult.  Two helper classes allow us to achieve this.

MvcControllerAdapter and ResultCapturingActionInvoker classes

Listing 6 – The MvcControllerAdapter Class
   1:  public class MvcControllerAdapter : IModuleController
   2:  {
   3:      #region Private Members
   4:   
   5:      private Controller _adaptedController;
   6:      private ResultCapturingActionInvoker _actionInvoker;
   7:   
   8:      #endregion
   9:   
  10:      #region Constructors
  11:   
  12:      public MvcControllerAdapter(Controller controller)
  13:      {
  14:          _adaptedController = controller;
  15:          _actionInvoker = new ResultCapturingActionInvoker();
  16:          _adaptedController.ActionInvoker = _actionInvoker;
  17:      }
  18:   
  19:      #endregion
  20:   
  21:      #region IModuleController Members
  22:   
  23:      public ActionResult ResultOfLastExecute
  24:      {
  25:          get { return _actionInvoker.ResultOfLastInvoke; }
  26:      }
  27:   
  28:      public ControllerContext ControllerContext
  29:      {
  30:          get { return _adaptedController.ControllerContext; }
  31:      }
  32:   
  33:      #endregion
  34:   
  35:      #region Public Methods
  36:   
  37:      public void Execute(RequestContext requestContext)
  38:      {
  39:          if (_adaptedController.ActionInvoker != _actionInvoker)
  40:          {
  41:              throw new InvalidOperationException("Could not construct Controller");
  42:          }
  43:          ((IController)_adaptedController).Execute(requestContext);
  44:      }
  45:   
  46:      #endregion
  47:   
  48:  }

The MvcControllerAdapter class (Listing 6) allows us to adapt standard MVC Framework Controller’s so that they implement the additional IModuleController interface.  The main job of the MvcControllerAdapter is to replace the Controller’s ActionInvoker with a ResultCapturingActionInvoker (line 15).  The ResultCapturingActionInvoker (Listing 7) captures the result of the Action and exposes it as the ResultofLastInvoke property.

Listing 7 – The ResultCapturingActionInvoker Class
   1:  public class ResultCapturingActionInvoker : ControllerActionInvoker
   2:  {
   3:      #region Public Properties
   4:   
   5:      public ActionResult ResultOfLastInvoke { get; set; }
   6:   
   7:      #endregion
   8:   
   9:      #region Protected Methods
  10:   
  11:      protected override void InvokeActionResult(ControllerContext controllerContext, 
  12:                                                  ActionResult actionResult)
  13:      {
  14:          // Do not invoke the action.  Instead, store it for later retrieval
  15:          ResultOfLastInvoke = actionResult;
  16:      }
  17:   
  18:      #endregion
  19:  }

So why do we need to capture the ActionResult? 

In the standard MVC Pipeline the next phase after invoking the action is to render the View.  DotNetNuke modules need to render their View inside the Container provided.  The ExecuteRequest method of the MvcModuleApplication class returns the ModuleRequestResult (which contains the captured ActionResult) and saves it in a private variable.

Now, we need to remember that the MvcModuleApplication class inherits from the base Control class.  DotNetNuke will have instantiated this class and added it to the Controls collection of the Container.  We use this fact in the RenderControl method to render our View, by executing the ActionResult (which as long as a ViewResult was returned will render the View inside the Container). (see Listing 8)

Listing 8 – MvcModuleApplication, RenderControl
   1:  public override void RenderControl(System.Web.UI.HtmlTextWriter writer)
   2:  {
   3:      if (_moduleResult != null)
   4:      {
   5:          //Execute the ActionResult
   6:          _moduleResult.ActionResult.ExecuteResult(_moduleResult.ControllerContext);
   7:      }
   8:  }

And that’s how its done.

Conclusions

So in conclusion the process used to enable MVC modules to be created is as follows.

  1. During the Init phase of the Page Lifecycle, mimic the MvcHandler to instantiate an MVC Controller class
  2. Adapt the Controller to modify its ActionInvoker so we can capture the ActionResult from the Controller’s action method.
  3. During the render phase of the Page LifeCycle, execute the returned ActionResult, to render the View.

Posted in: DotNetNuke  Tags: , , ,

In an earlier blog I introduced the idea of using ASP.NET MVC to develop DotNetNuke modules, and I walked through how you could create a simple ASP.NET MVC Module Application.  Now that I have demonstrated that it is feasible to use the MVC Framework in a WebForms Application, I will start to dig into how this was done.

But first, before we look at the code, lets review how the standard ASP.NET MVC Pipeline works. This is summarized effectively by Steve Sanderson, on his blog.

Figure 1 – ASP.NET MVC Pipeline

This diagram was based on an early Preview of the ASP.NET MVC Framework, but the basic process has not changed.  There are 4 stages in the standard ASP.NET MVC pipeline; Routing, Instantiate Controller, Locate and Execute Action, Instantiate and Render View.

Routing

In the routing step the Incoming Http Request is mapped to the MvcHandler and the MvcHandler’s ProcessRequest method is called, assuming of course that you have registered the handler in your web.config file (Listing 1).

Listing 1 – Registering the MVCHttpHandler in web.config
<add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.mvc" 
type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=31BF3856AD364E35"
/>


Controller Instantiation

The ProcessRequest method (Listing 2) creates a ControllerFactory (line 8), which in term attempts to create a Controller (line 9), using the RouteData  which is part of the RequestContext.  Assuming that the ControllerFactory is able to create a Controller Instance, ProcessRequest will call the Execute method of the Controller (line 19), thus passing control to the Controller.

Listing 2 – MvcHandler, ProcessRequest method
   1:  protected internal virtual void ProcessRequest(HttpContextBase httpContext) {
   2:      AddVersionHeader(httpContext);
   3:   
   4:      // Get the controller type
   5:      string controllerName = RequestContext.RouteData.GetRequiredString("controller");
   6:   
   7:      // Instantiate the controller and call Execute
   8:      IControllerFactory factory = ControllerBuilder.GetControllerFactory();
   9:      IController controller = factory.CreateController(RequestContext, controllerName);
  10:      if (controller == null) {
  11:          throw new InvalidOperationException(
  12:              String.Format(
  13:                  CultureInfo.CurrentUICulture,
  14:                  MvcResources.ControllerBuilder_FactoryReturnedNull,
  15:                  factory.GetType(),
  16:                  controllerName));
  17:      }
  18:      try {
  19:          controller.Execute(RequestContext);
  20:      }
  21:      finally {
  22:          factory.ReleaseController(controller);
  23:      }
  24:  }


Action Invoker

We have now successfully routed control to the appropriate Controller. 

The Execute method of the ControllerBase class calls the ExecuteCore (Listing 3) method of the Controller class.  This in turn calls the ActionInvoker (line 6), which again uses the RouteData to invoke the specific action on the Controller. 

Listing 3 – Controller, ExecuteCore method
   1:  protected override void ExecuteCore() {
   2:      TempData.Load(ControllerContext, TempDataProvider);
   3:   
   4:      try {
   5:          string actionName = RouteData.GetRequiredString("action");
   6:          if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) {
   7:              HandleUnknownAction(actionName);
   8:          }
   9:      }
  10:      finally {
  11:          TempData.Save(ControllerContext, TempDataProvider);
  12:      }
  13:  }

An action maps to a method name in the Controller class.

Listing 4 – The HomeController class
   1:  public class HomeController : Controller
   2:  {
   3:      public ActionResult Index()
   4:      {
   5:          ViewData["Message"] = "Welcome to ASP.NET MVC!";
   6:   
   7:          return View();
   8:      }
   9:   
  10:      public ActionResult About()
  11:      {
  12:          return View();
  13:      }
  14:  }

For example in Listing 4 which shows the HomeController in the default ASP.NET MVC project – the Index and About methods represent the index and about actions of the HomeController. 

You would reach these methods using the routes “/home/index” and “/home/about”, although as the first route represents the default controller “home” and the default action “index”, the null route would also reach the Index method.

Render View

Finally the ActionInvoker gets the returned ActionResult from the action method ands calls its ExecuteResult method.  If the ActionResult is a ViewResult (Listing 5) this in turn will render the View (line 17).

Listing 5 – ViewResultBase, ExecuteResult
   1:  public override void ExecuteResult(ControllerContext context) {
   2:      if (context == null) {
   3:          throw new ArgumentNullException("context");
   4:      }
   5:      if (String.IsNullOrEmpty(ViewName)) {
   6:          ViewName = context.RouteData.GetRequiredString("action");
   7:      }
   8:   
   9:      ViewEngineResult result = null;
  10:   
  11:      if (View == null) {
  12:          result = FindView(context);
  13:          View = result.View;
  14:      }
  15:   
  16:      ViewContext viewContext = new ViewContext(context, View, ViewData, TempData);
  17:      View.Render(viewContext, context.HttpContext.Response.Output);
  18:   
  19:      if (result != null) {
  20:          result.ViewEngine.ReleaseView(context, View);
  21:      }
  22:  }


Plugging in to the ASP.NET MVC Pipeline

So, given that DotNetNuke is a WebForms Application how do we plug in to this Pipeline with the least possible impact .  What I mean by this is that we don’t want to have to rewrite the MVC Framework in order to get everything to work.  We want to be able to use all of the extensibility points that the Framework enables, with a minimum amount of effort.

In the next part of this series I will describe how we achieve this goal.


Posted in: DotNetNuke  Tags: , , ,

Last week, Shaun posted a blog in which he discussed whether DotNetNuke (DNN) should be rewritten in ASP.NET MVC.  This blog created quite a stir, both within the DotNetNuke Community and within the ASP.NET Community as a whole. 

In a comment that I added to Shaun’s post I suggested that the debate should not be over whether DNN should be rewritten in ASP.NET MVC (or any other framework that may come in the future), the discussion should be on “How can we enable developers to use the ASP.NET Technologies of their choice when developing extensions for DNN.”  After all, if we rewrite DNN in MVC we effectively lock out WebForm developers.

Thanks to an idea from my son Andrew (much of what I used in this work was from his Maverick project on codeplex) I have been able the create a Framework that sits on top of DotNetNuke (and System.Web.MVC) and allows modules to be created using the ASP.NET MVC Framework (DotNetNuke.Web.Mvc).

In this article I will review how – using this add-on layer we can go about creating a simple ASP.NET MVC module.  First, add an ASP.NET MVC Application to your Visual Studio solution. (See Figure 1 below)

Figure 1 – Add a new MVC Web Application in the Desktop Modules folder called MVC_Test
MVCModule01

Note that the location of the project is in the DesktopModules folder of our test website.  This is exactly the same process we would use to add a WAP (Web Application Project) style module. Figure 2 below shows the Solution Explorer after adding this project.

Figure 2 – The new Project in Solution Explorer
MVCModule02

Before we go any further – we should prove to ourselves that this is a valid ASP.NET MVC Web Application, by selecting the Default.aspx file, and selecting View in Browser from the Context menu (see Figure 3 below)

Figure 3 – Browsing to the site demonstrates that this is a valid ASP.NET MVC Application
MVCModule03

So now we have an MVC Application, how do we make it run as a Module in our DotNetNuke website?  First we need to add a new class to our project – MVC_TestApplication.cs (see Figure 4).

Figure 4 – Add a new class MVC_TestApplication to the root of the Application
MVCModule04

And we need to add references to our DotNetNuke Library project and to the new DotNetNuke.Web.Mvc project (see Figure 5)

Figure 5 – Add references to the DotNetNuke Library and the new DotNetNuke.Web.Mvc project
MVCModule05

When we have done that we need to open the new class we added and add some very simple code.

Listing 1 – The MVc_TestApplication class
   1:  using System.Web.Routing;
   2:  using DotNetNuke.Web.Mvc;
   3:  using DotNetNuke.Web.Mvc.Routing;
   4:   
   5:  namespace MVC_Test
   6:  {
   7:      public class MVC_TestApplication : MvcModuleApplication 
   8:      {
   9:          protected override string FolderPath 
  10:          {
  11:              get { return "MVC_Test"; }
  12:          }
  13:   
  14:          protected override void Init() 
  15:          {
  16:              base.Init();
  17:              RegisterRoutes(Routes);
  18:          }
  19:   
  20:          private static void RegisterRoutes(RouteCollection routes) 
  21:          {
  22:              routes.RegisterDefaultRoute("MVC_Test.Controllers");
  23:          }
  24:      }
  25:  }

The most important thing to note is that this class inherits from MvcModuleApplication, a new base class in the new DotNetNuke.Web.Mvc project.  The Init method allows us to register any routes that our MVC Module Application will need and the FolderPath property tells the DotNetNuke.Web.Mvc project where our Views are located.  Finally we need to make a very small change to the default View (Listing 2).

Listing 2 – Index.aspx
   1:  <%@ Page Language="C#" MasterPageFile="../Shared/Site.Master" 
Inherits="System.Web.Mvc.ViewPage" %>
   2:   
   3:  <asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">
   4:      Home Page
   5:  </asp:Content>
   6:   
   7:  <asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
   8:      <h2><%= Html.Encode(ViewData["Message"]) %></h2>
   9:      <p>
  10:          To learn more about ASP.NET MVC visit <a href=http://asp.net/mvc 
                               title="ASP.NET MVC Website">http://asp.net/mvc</a>.
  11:      </p>
  12:  </asp:Content>

If you blink you won’t see the change. 

The change is to the reference to the MasterPageFile – the value of the attribute is changed from “~/Views/Shared/Site.Master” to “../Views/Shared/Site.Master”.  The reference points to the same file – but the original reference assumes that the Views folder is at the root of the IIS Application – as a module it is actually at ~/DesktopModules/MVC_Test/Views”.  By making the reference relative it will work in both scenarios.

Next we need to create our Module Extension.  This is done in much the same way as we do today, the only difference being that when we register the Module Control we use the Namespace for the new class that we added – MVC_Test.MVC_TestApplication (See Figure 6 below).  Since version 5.0, DNN has allowed module controls to be server controls and ultimately our new MVC_TestApplication class inherits from Control.

Figure 6 – Add the MVC_TestApplication as the Source for the Default Module Control
MVCModule06

Finally build our new MVC Module Application and copy the assembly from the bin folder of the project to the bin folder of the Website.

We are now ready to see if everything works.  Add a new Page and add the newly registered Module to the Page and “hey presto” we get a Module that looks like the MVC Application (See Figure 7 below)

Figure 7 – Add the Module to the Page
MVCModule07

The really cool thing is that we can still browse to the site (as an MVC Application) by selecting the Default.aspx page, and selecting View in Browser from the context menu, as we did in Figure 3 above.

Conclusions

In summary I have demonstrated in this article, that using ASP.NET MVC for Module Development is a possibility.  There still are a number of issues to resolve however, including, but not limited to:

  1. Handling routes other than the default route.
  2. Do the Html Helpers in ASP.NET MVC still work? and if not how can we make them work?
  3. As Webforms allows only one Form tag which is defined in the base page -Default.aspx -how do we handle Forms in an MVC Module.
  4. Issues around the use of Master pages and styles, and DNN skinning – we can solve this by removing the dependency on Master pages which is not a requirement of ASP.NET MVC.

I don’t expect any of these to be show-stoppers, but much more work still needs to be done.  In future blogs, I will describe how what I describe in this article was done and report on my attempts to resolve the remaining issues.


Posted in: DotNetNuke  Tags: , , ,

 Search Blog

 Adsense

 Calendar

«  September 2010  »
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910
View posts in large calendar

 Tags

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010 Thoughts from the Wet Coast