Permalink
Browse files

Rest + CodeGenerator project updates to support /path/to/resource.for…

…mat restful route generation. Made Rest project a bit more flexible for customization of behaviour. Finally, if no responder is currently set up for an explicitly selected format, the controller falls back to supplying the next best acceptable format.
  • Loading branch information...
1 parent 429ecfb commit 58f3763c15211ce616ecfe6b2d6e5c5842356207 lee.m.henson committed Jan 13, 2009
Showing with 315 additions and 129 deletions.
  1. +2 −2 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest.Tests/Castle.MonoRail.Rest.Tests.csproj
  2. +0 −11 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest.Tests/ControllerBridgeFixture.cs
  3. +0 −21 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest.Tests/DefaultUrlProviderFixture.cs
  4. +7 −4 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest.Tests/ResponseFormatFixture.cs
  5. +6 −9 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest.Tests/ResponseHandlerFixture.cs
  6. +67 −0 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest.Tests/UrlWithExtensionParserTests.cs
  7. +7 −0 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest/Castle.MonoRail.Rest.csproj
  8. BIN Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest/CastleKey.snk
  9. +18 −20 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest/ControllerBridge.cs
  10. +1 −3 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest/IControllerBridge.cs
  11. +4 −9 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest/Mime/MimeType.cs
  12. +59 −17 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest/Responder.cs
  13. +4 −8 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest/ResponseFormat.cs
  14. +4 −16 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest/ResponseHandler.cs
  15. +17 −5 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest/RestfulController.cs
  16. +6 −0 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest/RestfulRoute.cs
  17. +47 −0 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest/RoutingAwareControllerBridge.cs
  18. +39 −0 Castle.MonoRail.Rest/trunk/Source/Castle.MonoRail.Rest/UrlWithExtensionParser.cs
  19. BIN Castle.MonoRail.Rest/trunk/lib/Boo.Lang.Compiler.dll
  20. BIN Castle.MonoRail.Rest/trunk/lib/Boo.Lang.Parser.dll
  21. BIN Castle.MonoRail.Rest/trunk/lib/Boo.Lang.dll
  22. BIN Castle.MonoRail.Rest/trunk/lib/Castle.ActiveRecord.dll
  23. BIN Castle.MonoRail.Rest/trunk/lib/Castle.ActiveRecord.pdb
  24. BIN Castle.MonoRail.Rest/trunk/lib/Castle.Components.Binder.dll
  25. BIN Castle.MonoRail.Rest/trunk/lib/Castle.Components.Common.EmailSender.dll
  26. BIN Castle.MonoRail.Rest/trunk/lib/Castle.Components.Validator.dll
  27. BIN Castle.MonoRail.Rest/trunk/lib/Castle.Core.dll
  28. BIN Castle.MonoRail.Rest/trunk/lib/Castle.DynamicProxy2.dll
  29. BIN Castle.MonoRail.Rest/trunk/lib/Castle.Facilities.ActiveRecordIntegration.dll
  30. BIN Castle.MonoRail.Rest/trunk/lib/Castle.Facilities.ActiveRecordIntegration.pdb
  31. BIN Castle.MonoRail.Rest/trunk/lib/Castle.Facilities.Logging.dll
  32. BIN Castle.MonoRail.Rest/trunk/lib/Castle.Facilities.Logging.pdb
  33. BIN Castle.MonoRail.Rest/trunk/lib/Castle.MicroKernel.dll
  34. BIN Castle.MonoRail.Rest/trunk/lib/Castle.MonoRail.Framework.Views.NVelocity.dll
  35. BIN Castle.MonoRail.Rest/trunk/lib/Castle.MonoRail.Framework.dll
  36. BIN Castle.MonoRail.Rest/trunk/lib/Castle.MonoRail.TestSupport.dll
  37. BIN Castle.MonoRail.Rest/trunk/lib/Castle.MonoRail.TestSupport.pdb
  38. BIN Castle.MonoRail.Rest/trunk/lib/Castle.MonoRail.Views.Brail.dll
  39. BIN Castle.MonoRail.Rest/trunk/lib/Castle.MonoRail.Views.Brail.pdb
  40. BIN Castle.MonoRail.Rest/trunk/lib/Castle.MonoRail.WindsorExtension.dll
  41. BIN Castle.MonoRail.Rest/trunk/lib/Castle.Services.Logging.Log4netIntegration.dll
  42. BIN Castle.MonoRail.Rest/trunk/lib/Castle.Services.Transaction.dll
  43. BIN Castle.MonoRail.Rest/trunk/lib/Castle.Services.Transaction.pdb
  44. BIN Castle.MonoRail.Rest/trunk/lib/Castle.Windsor.dll
  45. BIN Castle.MonoRail.Rest/trunk/lib/Iesi.Collections.dll
  46. BIN Castle.MonoRail.Rest/trunk/lib/NHibernate.dll
  47. BIN Castle.MonoRail.Rest/trunk/lib/NVelocity.dll
  48. +4 −4 codegenerator/trunk/Castle.Tools.CodeGenerator.RestfulRouting/RestRoutesAttribute.cs
  49. +10 −0 ...or/trunk/Castle.Tools.CodeGenerator/Services/Generators/RouteMapGeneration/PatternRouteCreator.cs
  50. +13 −0 ...rator/trunk/Castle.Tools.CodeGenerator/Services/Generators/RouteMapGeneration/RestRouteCreator.cs
  51. BIN codegenerator/trunk/Libraries/Castle.Components.Binder.dll
  52. BIN codegenerator/trunk/Libraries/Castle.Components.Common.EmailSender.dll
  53. BIN codegenerator/trunk/Libraries/Castle.Components.Validator.dll
  54. BIN codegenerator/trunk/Libraries/Castle.Core.dll
  55. BIN codegenerator/trunk/Libraries/Castle.DynamicProxy2.dll
  56. BIN codegenerator/trunk/Libraries/Castle.MonoRail.Framework.dll
  57. BIN codegenerator/trunk/Libraries/Castle.MonoRail.Rest.dll
@@ -3,7 +3,7 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>9.0.20706</ProductVersion>
+ <ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{A56397CD-B09F-4700-A2C1-AB7E4C4006B1}</ProjectGuid>
<OutputType>Library</OutputType>
@@ -71,12 +71,12 @@
<ItemGroup>
<Compile Include="Binding\XmlBindAttributeFixture.cs" />
<Compile Include="Binding\XmlTreeBuilderFixture.cs" />
- <Compile Include="ControllerBridgeFixture.cs" />
<Compile Include="DefaultUrlProviderFixture.cs" />
<Compile Include="Mime\AcceptTypeParsingFixture.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ResponseFormatFixture.cs" />
<Compile Include="ResponseHandlerFixture.cs" />
+ <Compile Include="UrlWithExtensionParserTests.cs" />
<Compile Include="Stubs\SampleRestController.cs" />
</ItemGroup>
<ItemGroup>
@@ -1,11 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace Castle.MonoRail.Rest.Tests
-{
- class ControllerBridgeFixture
- {
- }
-}
@@ -6,31 +6,12 @@
using Castle.MonoRail.Framework.Services;
using Castle.MonoRail.Framework;
using Castle.MonoRail.Rest.Tests.Stubs;
-using Castle.MonoRail.Framework.Configuration;
using Rhino.Mocks;
namespace Castle.MonoRail.Rest.Tests
{
[TestFixture]
public class DefaultUrlProviderFixture
{
- //private DefaultControllerTree controllerTree;
- //private DefaultUrlTokenizer tokenizer;
- //private DefaultUrlProvider provider;
-
-
- //[SetUp]
- //public void SetUp()
- //{
- // StubServiceProvider serviceProvider = new StubServiceProvider(this);
- // controllerTree = new DefaultControllerTree();
- // tokenizer = new DefaultUrlTokenizer();
-
- // provider = new DefaultUrlProvider();
- // provider.Service(serviceProvider);
-
- // controllerTree.AddController("v1", "samplerest", typeof(SampleRestController));
- //}
-
[Test]
public void Should_AddTwoUrls_WhenControllerAddedToTree()
{
@@ -59,7 +40,6 @@ public void Should_AddTwoUrls_WhenControllerAddedToTree()
public class StubServiceProvider : IServiceProvider
{
-
private IUrlTokenizer tokenizer;
private IControllerTree controllerTree;
@@ -81,6 +61,5 @@ public object GetService(Type serviceType)
}
return null;
}
-
}
}
@@ -1,4 +1,5 @@
using System.Linq;
+using Castle.MonoRail.Rest.Mime;
using MbUnit.Framework;
using Rhino.Mocks;
@@ -22,15 +23,17 @@ public void IfRespondWithMimeAll_ThenFirstResponder_ShouldBeInvoked()
{
SetupResult.For(bridge.ControllerAction).Return("Show");
}
- string handlerInvoked = "";
- format = (ResponseFormatInternal)new ResponseFormat();
+
+ string handlerInvoked = "";
+ MimeTypes mimeTypes = new MimeTypes();
+ mimeTypes.RegisterBuiltinTypes();
+
+ format = (ResponseFormatInternal)new ResponseFormat(mimeTypes);
format.AddRenderer("html", response => handlerInvoked = "html");
format.AddRenderer("xml", response => handlerInvoked = "xml");
format.RespondWith("all", bridge);
Assert.AreEqual("html", handlerInvoked);
}
-
-
}
}
@@ -1,5 +1,4 @@
-using System.Linq;
-using MbUnit.Framework;
+using MbUnit.Framework;
using Rhino.Mocks;
using Castle.MonoRail.Rest.Mime;
@@ -12,24 +11,22 @@ public class ResponseHandlerFixture
private MockRepository mocks;
private ResponseFormat format;
private string handlerInvoked;
- private MimeType[] mimes;
+ private MimeTypes mimes;
[SetUp]
public void Setup()
{
+ mimes = new MimeTypes();
+ mimes.RegisterBuiltinTypes();
+
mocks = new MockRepository();
bridge = mocks.DynamicMock<IControllerBridge>();
- format = new ResponseFormat();
+ format = new ResponseFormat(mimes);
handlerInvoked = "";
ResponseFormatInternal iformat = (ResponseFormatInternal)format;
iformat.AddRenderer("xml", x => handlerInvoked = "xml");
iformat.AddRenderer("html", x => handlerInvoked = "html");
-
- mimes = new MimeType[] {
- new MimeType() { Symbol="html",MimeString="text/html"},
- new MimeType() { Symbol="xml",MimeString="application/xml"}
- };
}
[Test]
@@ -0,0 +1,67 @@
+using MbUnit.Framework;
+
+namespace Castle.MonoRail.Rest.Tests
+{
+ [TestFixture]
+ public class UrlWithExtensionParserTests
+ {
+ UrlWithExtensionParser parser;
+
+ [SetUp]
+ public void SetUp()
+ {
+ parser = new UrlWithExtensionParser();
+ }
+
+ [Test]
+ public void WithUrlThatHasNoExtension_ShouldReturnCorrectParts()
+ {
+ var url = "/path/to/resource";
+ var parts = parser.GetParts(url);
+
+ Assert.AreEqual(3, parts.Length);
+ Assert.AreEqual("path", parts[0]);
+ Assert.AreEqual("to", parts[1]);
+ Assert.AreEqual("resource", parts[2]);
+ }
+
+ [Test]
+ public void WithUrlThatHasASingleDotInTheFinalSegment_ShouldReturnCorrectParts()
+ {
+ var url = "/path/to/resource.json";
+ var parts = parser.GetParts(url);
+
+ Assert.AreEqual(4, parts.Length);
+ Assert.AreEqual("path", parts[0]);
+ Assert.AreEqual("to", parts[1]);
+ Assert.AreEqual("resource", parts[2]);
+ Assert.AreEqual("json", parts[3]);
+ }
+
+ [Test]
+ public void WithUrlThatHasMultipleDotsInTheFinalSegment_ShouldReturnCorrectParts()
+ {
+ var url = "/path/to/resource.with.dots.json";
+ var parts = parser.GetParts(url);
+
+ Assert.AreEqual(4, parts.Length);
+ Assert.AreEqual("path", parts[0]);
+ Assert.AreEqual("to", parts[1]);
+ Assert.AreEqual("resource.with.dots", parts[2]);
+ Assert.AreEqual("json", parts[3]);
+ }
+
+ [Test]
+ public void WithUrlThatHasMultipleDotsInEarlierSegments_ShouldReturnCorrectParts()
+ {
+ var url = "/path/with.dots/leading.to/resource";
+ var parts = parser.GetParts(url);
+
+ Assert.AreEqual(4, parts.Length);
+ Assert.AreEqual("path", parts[0]);
+ Assert.AreEqual("with.dots", parts[1]);
+ Assert.AreEqual("leading.to", parts[2]);
+ Assert.AreEqual("resource", parts[3]);
+ }
+ }
+}
@@ -12,6 +12,8 @@
<AssemblyName>Castle.MonoRail.Rest</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>CastleKey.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -75,10 +77,15 @@
<Compile Include="RestfulEngineContextFactory.cs" />
<Compile Include="RestfulRequestAdapter.cs" />
<Compile Include="RestfulRoute.cs" />
+ <Compile Include="RoutingAwareControllerBridge.cs" />
+ <Compile Include="UrlWithExtensionParser.cs" />
</ItemGroup>
<ItemGroup>
<Service Include="{B4F97281-0DBD-4835-9ED8-7DFB966E87FF}" />
</ItemGroup>
+ <ItemGroup>
+ <None Include="CastleKey.snk" />
+ </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
@@ -15,9 +15,6 @@
namespace Castle.MonoRail.Rest
{
using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
using Castle.MonoRail.Rest.Mime;
using System.IO;
@@ -32,54 +29,57 @@ public ControllerBridge(RestfulController controller, string controllerAction)
_controllerAction = controllerAction;
}
- public void SetResponseType(MimeType mime)
+ public virtual void SetResponseType(MimeType mime)
{
_controller.Response.ContentType = mime.MimeString;
}
- public void SendRenderView(string view)
+ public virtual void SendRenderView(string view)
{
_controller.RenderView(view);
}
- public void SendCancelLayoutAndView()
+ public virtual void SendCancelLayoutAndView()
{
_controller.CancelLayout();
_controller.CancelView();
}
- public void UseResponseWriter(Action<TextWriter> writerAction)
+ public virtual void UseResponseWriter(Action<TextWriter> writerAction)
{
writerAction(_controller.Response.Output);
}
- public void SetResponseCode(int code)
+ public virtual void UseResponseStream(Action<Stream> streamAction)
+ {
+ streamAction(_controller.Response.OutputStream);
+ }
+
+ public virtual void SetResponseCode(int code)
{
_controller.Response.StatusCode = code;
}
- public void AppendResponseHeader(string headerName, string value)
+ public virtual void AppendResponseHeader(string headerName, string value)
{
_controller.Response.AppendHeader(headerName, value);
}
- public void SendRenderText(string text)
+ public virtual void SendRenderText(string text)
{
_controller.RenderText(text);
}
- #region IControllerBridge Members
-
-
- public string ControllerAction
+ public virtual string ControllerAction
{
get { return _controllerAction; }
}
- public bool IsFormatDefined
+ public virtual bool IsFormatDefined
{
- get {
- if (String.IsNullOrEmpty(_controller.Params["format"]))
+ get
+ {
+ if (String.IsNullOrEmpty(GetFormat()))
{
return false;
}
@@ -90,11 +90,9 @@ public bool IsFormatDefined
}
}
- public string GetFormat()
+ public virtual string GetFormat()
{
return _controller.Params["format"];
}
-
- #endregion
}
}
@@ -15,9 +15,6 @@
namespace Castle.MonoRail.Rest
{
using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
using Castle.MonoRail.Rest.Mime;
using System.IO;
@@ -27,6 +24,7 @@ public interface IControllerBridge
void SendRenderView(string view);
void SendCancelLayoutAndView();
void UseResponseWriter(Action<TextWriter> writerAction);
+ void UseResponseStream(Action<Stream> streamAction);
void SetResponseCode(int code);
void AppendResponseHeader(string headerName, string value);
void SendRenderText(string text);
@@ -17,17 +17,13 @@ namespace Castle.MonoRail.Rest.Mime
using System;
using System.Collections.Generic;
using System.Linq;
- using System.Text;
-
+
public class MimeType
{
-
public string MimeString { get; set; }
public string Symbol {get; set;}
public List<String> Synonyms { get; set; }
- public List<String> ExtensionSynonyms { get; set; }
-
-
+ public List<String> ExtensionSynonyms { get; set; }
}
public class MimeTypes : System.Collections.Generic.List<MimeType>
@@ -46,7 +42,7 @@ public void RegisterBuiltinTypes()
Register("text/javascript", "js", new[] { "application/javascript", "application/x-javascript" });
Register("text/css", "css");
Register("text/calendar", "ics");
- Register("text/csv", "csv");
+ Register("text/csv", "csv", new[] { "application/csv", "application/vnd.ms-excel" });
Register("application/xml", "xml", new[] { "text/xml application/x-xml" });
Register("application/rss+xml", "rss");
Register("application/atom+xml", "atom");
@@ -55,8 +51,7 @@ public void RegisterBuiltinTypes()
Register("application/x-www-form-urlencoded", "url_encoded_form");
//http://www.ietf.org/rfc/rfc4627.txt
- Register("application/json", "json", new[] { "text/x-json" });
-
+ Register("application/json", "json", new[] { "text/x-json" });
}
public void Register(string mimeString, string symbol)
Oops, something went wrong.

0 comments on commit 58f3763

Please sign in to comment.