[{"data":1,"prerenderedAt":999},["ShallowReactive",2],{"blog:2007:rails-style-controllers-for-aspnet":3,"blogMore-Development":985,"comments-rails-style-controllers-for-aspnet":998},{"id":4,"title":5,"body":6,"category":967,"commentCount":74,"date":968,"description":969,"excerpt":970,"extension":971,"filenames":972,"hidden":973,"image":972,"meta":974,"minutes":209,"navigation":212,"path":975,"seo":976,"showCategory":972,"stem":977,"tags":978,"updated":972,"url":982,"wordCount":983,"__hash__":984},"content\u002Fblog\u002F2007\u002Frails-style-controllers-for-aspnet.md","Rails-style controllers for ASP.NET",{"type":7,"value":8,"toc":962},"minimark",[9,31,45,50,61,148,155,275,278,428,433,919,922,926,929,932,939,943,946,949,952,958],[10,11,12,19,20,25,26,30],"p",{},[13,14,18],"a",{"href":15,"rel":16},"https:\u002F\u002Fblog.wekeroad.com",[17],"nofollow","Rob Conery"," has been putting together some great screen casts on ",[13,21,24],{"href":22,"rel":23},"https:\u002F\u002Fsubsonicproject.com",[17],"SubSonic"," and his latest on generating controllers pointed out that ASP.NET doesn’t support the Rails-style ",[13,27,28],{"href":28,"rel":29},"http:\u002F\u002Fsite\u002F\u002Fcontroller\u002Fmethod",[17]," style of execution.",[10,32,33,34,39,40,44],{},"This got me excited and I’ve put together a ",[13,35,38],{"href":36,"rel":37},"https:\u002F\u002Fdl.damieng.com\u002Fdotnet\u002FRailsControllers.zip",[17],"proof-of-concept web project"," that demonstrates mapping the path to controller methods using an ",[41,42,43],"code",{},"IHttpHandler"," and reflection.",[46,47,49],"h2",{"id":48},"how-it-works","How it works",[10,51,52,53,56,57,60],{},"It registers the ",[41,54,55],{},"ControllerHttpHandler"," via the ",[41,58,59],{},"web.config",":",[62,63,68],"pre",{"className":64,"code":65,"language":66,"meta":67,"style":67},"language-xml shiki shiki-themes everforest-light dracula","\u003ChttpHandlers>\n  \u003Cadd path=\"\u002Fctl\u002F\\*\u002F\\*\" verb=\"POST,GET,HEAD\" type=\"ControllerHttpHandler\" \u002F>\n\u003C\u002FhttpHandlers>\n","xml","",[41,69,70,86,138],{"__ignoreMap":67},[71,72,75,79,83],"span",{"class":73,"line":74},"line",1,[71,76,78],{"class":77},"sNvvj","\u003C",[71,80,82],{"class":81},"s9HRq","httpHandlers",[71,84,85],{"class":77},">\n",[71,87,89,92,95,99,102,106,110,112,115,117,119,122,124,127,129,131,133,135],{"class":73,"line":88},2,[71,90,91],{"class":77},"  \u003C",[71,93,94],{"class":81},"add",[71,96,98],{"class":97},"sr8dK"," path",[71,100,101],{"class":77},"=",[71,103,105],{"class":104},"sciFF","\"",[71,107,109],{"class":108},"sJQOs","\u002Fctl\u002F\\*\u002F\\*",[71,111,105],{"class":104},[71,113,114],{"class":97}," verb",[71,116,101],{"class":77},[71,118,105],{"class":104},[71,120,121],{"class":108},"POST,GET,HEAD",[71,123,105],{"class":104},[71,125,126],{"class":97}," type",[71,128,101],{"class":77},[71,130,105],{"class":104},[71,132,55],{"class":108},[71,134,105],{"class":104},[71,136,137],{"class":77}," \u002F>\n",[71,139,141,144,146],{"class":73,"line":140},3,[71,142,143],{"class":77},"\u003C\u002F",[71,145,82],{"class":81},[71,147,85],{"class":77},[10,149,150,151,154],{},"There is a very basic ",[41,152,153],{},"Controller"," abstract base class that just provides a simple way of accessing the context for dealing with request\u002Fresponse for now.",[62,156,160],{"className":157,"code":158,"language":159,"meta":67,"style":67},"language-csharp shiki shiki-themes everforest-light dracula","public abstract class Controller\n{\n  protected System.Web.HttpContext context;\n\n  internal Controller(System.Web.HttpContext context) {\n    this.context = context;\n  }\n}\n","csharp",[41,161,162,178,184,207,214,245,263,269],{"__ignoreMap":67},[71,163,164,167,170,174],{"class":73,"line":74},[71,165,166],{"class":81},"public",[71,168,169],{"class":81}," abstract",[71,171,173],{"class":172},"smiwp"," class",[71,175,177],{"class":176},"sPLAf"," Controller\n",[71,179,180],{"class":73,"line":88},[71,181,183],{"class":182},"s6Vpi","{\n",[71,185,186,189,193,196,199,201,204],{"class":73,"line":140},[71,187,188],{"class":81},"  protected",[71,190,192],{"class":191},"snuxY"," System",[71,194,195],{"class":182},".",[71,197,198],{"class":191},"Web",[71,200,195],{"class":182},[71,202,203],{"class":191},"HttpContext",[71,205,206],{"class":182}," context;\n",[71,208,210],{"class":73,"line":209},4,[71,211,213],{"emptyLinePlaceholder":212},true,"\n",[71,215,217,220,224,227,230,232,234,236,238,242],{"class":73,"line":216},5,[71,218,219],{"class":81},"  internal",[71,221,223],{"class":222},"sS4Kt"," Controller",[71,225,226],{"class":182},"(",[71,228,229],{"class":191},"System",[71,231,195],{"class":182},[71,233,198],{"class":191},[71,235,195],{"class":182},[71,237,203],{"class":191},[71,239,241],{"class":240},"s7cAX"," context",[71,243,244],{"class":182},") {\n",[71,246,248,252,254,258,261],{"class":73,"line":247},6,[71,249,251],{"class":250},"sKO3f","    this",[71,253,195],{"class":182},[71,255,257],{"class":256},"sSKRk","context",[71,259,260],{"class":81}," =",[71,262,206],{"class":182},[71,264,266],{"class":73,"line":265},7,[71,267,268],{"class":182},"  }\n",[71,270,272],{"class":73,"line":271},8,[71,273,274],{"class":182},"}\n",[10,276,277],{},"We then have a test controller or two that implement from this with a couple of methods and the required constructor:",[62,279,281],{"className":157,"code":280,"language":159,"meta":67,"style":67},"public class TestController : Controller\n{\n  public TestController(System.Web.HttpContext context) : base(context) { }\n\n  public void Index() {\n    context.Response.Write(\"This is the index\");\n  }\n\n  public void Welcome() {\n    context.Response.Write(\"Welcome to the TestController\");\n  }\n}\n",[41,282,283,298,302,333,337,351,376,380,384,396,418,423],{"__ignoreMap":67},[71,284,285,287,289,292,295],{"class":73,"line":74},[71,286,166],{"class":81},[71,288,173],{"class":172},[71,290,291],{"class":176}," TestController",[71,293,294],{"class":182}," : ",[71,296,297],{"class":191},"Controller\n",[71,299,300],{"class":73,"line":88},[71,301,183],{"class":182},[71,303,304,307,309,311,313,315,317,319,321,323,326,330],{"class":73,"line":140},[71,305,306],{"class":81},"  public",[71,308,291],{"class":222},[71,310,226],{"class":182},[71,312,229],{"class":191},[71,314,195],{"class":182},[71,316,198],{"class":191},[71,318,195],{"class":182},[71,320,203],{"class":191},[71,322,241],{"class":240},[71,324,325],{"class":182},") : ",[71,327,329],{"class":328},"stJs5","base",[71,331,332],{"class":182},"(context) { }\n",[71,334,335],{"class":73,"line":209},[71,336,213],{"emptyLinePlaceholder":212},[71,338,339,341,345,348],{"class":73,"line":216},[71,340,306],{"class":81},[71,342,344],{"class":343},"sXAHl"," void",[71,346,347],{"class":222}," Index",[71,349,350],{"class":182},"() {\n",[71,352,353,356,359,361,364,366,368,371,373],{"class":73,"line":247},[71,354,355],{"class":182},"    context.",[71,357,358],{"class":256},"Response",[71,360,195],{"class":182},[71,362,363],{"class":222},"Write",[71,365,226],{"class":182},[71,367,105],{"class":104},[71,369,370],{"class":108},"This is the index",[71,372,105],{"class":104},[71,374,375],{"class":182},");\n",[71,377,378],{"class":73,"line":265},[71,379,268],{"class":182},[71,381,382],{"class":73,"line":271},[71,383,213],{"emptyLinePlaceholder":212},[71,385,387,389,391,394],{"class":73,"line":386},9,[71,388,306],{"class":81},[71,390,344],{"class":343},[71,392,393],{"class":222}," Welcome",[71,395,350],{"class":182},[71,397,399,401,403,405,407,409,411,414,416],{"class":73,"line":398},10,[71,400,355],{"class":182},[71,402,358],{"class":256},[71,404,195],{"class":182},[71,406,363],{"class":222},[71,408,226],{"class":182},[71,410,105],{"class":104},[71,412,413],{"class":108},"Welcome to the TestController",[71,415,105],{"class":104},[71,417,375],{"class":182},[71,419,421],{"class":73,"line":420},11,[71,422,268],{"class":182},[71,424,426],{"class":73,"line":425},12,[71,427,274],{"class":182},[10,429,430,431,60],{},"Finally the magic that joins them up is the ",[41,432,55],{},[62,434,436],{"className":157,"code":435,"language":159,"meta":67,"style":67},"using System;\nusing System.Web;\nusing System.Reflection;\n\npublic class ControllerHttpHandler : IHttpHandler\n{\n  public void ProcessRequest(HttpContext context) {\n    string[] parts = context.Request.Path.Split('\u002F');\n    if (parts.Length \u003C 4) {\n      context.Response.Write(\"No controller & member specified\");\n      return;\n    }\n\n    string controllerName = parts[2];\n    string methodName = parts[3];\n    Type potentialController = Type.GetType(controllerName);\n    if (potentialController != null && potentialController.IsClass && potentialController.IsSubclassOf(typeof(Controller))) {\n      MethodInfo potentialMethod = potentialController.GetMethod(methodName);\n      if (potentialMethod != null) {\n        Controller controller = (Controller) Activator.CreateInstance(potentialController, context);\n        potentialMethod.Invoke(controller, null);\n      }\n      else\n        context.Response.Write(String.Format(\"Method '{0}' not found on controller '{1}'\", methodName, controllerName));\n    }\n    else\n      context.Response.Write(String.Format(\"Controller '{0}' not found\", controllerName));\n  }\n\n  public bool IsReusable {\n    get { return false; }\n  }\n}\n",[41,437,438,449,461,474,478,492,496,513,552,572,594,601,606,611,633,652,672,714,733,748,773,790,796,802,832,837,843,870,875,880,891,909,914],{"__ignoreMap":67},[71,439,440,443,446],{"class":73,"line":74},[71,441,442],{"class":172},"using",[71,444,192],{"class":445},"sjYfO",[71,447,448],{"class":182},";\n",[71,450,451,453,455,457,459],{"class":73,"line":88},[71,452,442],{"class":172},[71,454,192],{"class":445},[71,456,195],{"class":182},[71,458,198],{"class":445},[71,460,448],{"class":182},[71,462,463,465,467,469,472],{"class":73,"line":140},[71,464,442],{"class":172},[71,466,192],{"class":445},[71,468,195],{"class":182},[71,470,471],{"class":445},"Reflection",[71,473,448],{"class":182},[71,475,476],{"class":73,"line":209},[71,477,213],{"emptyLinePlaceholder":212},[71,479,480,482,484,487,489],{"class":73,"line":216},[71,481,166],{"class":81},[71,483,173],{"class":172},[71,485,486],{"class":176}," ControllerHttpHandler",[71,488,294],{"class":182},[71,490,491],{"class":191},"IHttpHandler\n",[71,493,494],{"class":73,"line":247},[71,495,183],{"class":182},[71,497,498,500,502,505,507,509,511],{"class":73,"line":265},[71,499,306],{"class":81},[71,501,344],{"class":343},[71,503,504],{"class":222}," ProcessRequest",[71,506,226],{"class":182},[71,508,203],{"class":191},[71,510,241],{"class":240},[71,512,244],{"class":182},[71,514,515,518,521,523,526,529,531,534,536,539,541,545,548,550],{"class":73,"line":271},[71,516,517],{"class":343},"    string",[71,519,520],{"class":182},"[] parts ",[71,522,101],{"class":81},[71,524,525],{"class":182}," context.",[71,527,528],{"class":256},"Request",[71,530,195],{"class":182},[71,532,533],{"class":256},"Path",[71,535,195],{"class":182},[71,537,538],{"class":222},"Split",[71,540,226],{"class":182},[71,542,544],{"class":543},"sFDqs","'",[71,546,547],{"class":108},"\u002F",[71,549,544],{"class":543},[71,551,375],{"class":182},[71,553,554,557,560,563,566,570],{"class":73,"line":386},[71,555,556],{"class":172},"    if",[71,558,559],{"class":182}," (parts.",[71,561,562],{"class":256},"Length",[71,564,565],{"class":81}," \u003C",[71,567,569],{"class":568},"s3Ipq"," 4",[71,571,244],{"class":182},[71,573,574,577,579,581,583,585,587,590,592],{"class":73,"line":398},[71,575,576],{"class":182},"      context.",[71,578,358],{"class":256},[71,580,195],{"class":182},[71,582,363],{"class":222},[71,584,226],{"class":182},[71,586,105],{"class":104},[71,588,589],{"class":108},"No controller & member specified",[71,591,105],{"class":104},[71,593,375],{"class":182},[71,595,596,599],{"class":73,"line":420},[71,597,598],{"class":172},"      return",[71,600,448],{"class":182},[71,602,603],{"class":73,"line":425},[71,604,605],{"class":182},"    }\n",[71,607,609],{"class":73,"line":608},13,[71,610,213],{"emptyLinePlaceholder":212},[71,612,614,616,619,621,624,627,630],{"class":73,"line":613},14,[71,615,517],{"class":343},[71,617,618],{"class":182}," controllerName ",[71,620,101],{"class":81},[71,622,623],{"class":256}," parts",[71,625,626],{"class":182},"[",[71,628,629],{"class":568},"2",[71,631,632],{"class":182},"];\n",[71,634,636,638,641,643,645,647,650],{"class":73,"line":635},15,[71,637,517],{"class":343},[71,639,640],{"class":182}," methodName ",[71,642,101],{"class":81},[71,644,623],{"class":256},[71,646,626],{"class":182},[71,648,649],{"class":568},"3",[71,651,632],{"class":182},[71,653,655,658,661,663,666,669],{"class":73,"line":654},16,[71,656,657],{"class":191},"    Type",[71,659,660],{"class":182}," potentialController ",[71,662,101],{"class":81},[71,664,665],{"class":182}," Type.",[71,667,668],{"class":222},"GetType",[71,670,671],{"class":182},"(controllerName);\n",[71,673,675,677,680,683,686,689,692,695,697,699,702,704,707,709,711],{"class":73,"line":674},17,[71,676,556],{"class":172},[71,678,679],{"class":182}," (potentialController ",[71,681,682],{"class":81},"!=",[71,684,685],{"class":568}," null",[71,687,688],{"class":81}," &&",[71,690,691],{"class":182}," potentialController.",[71,693,694],{"class":256},"IsClass",[71,696,688],{"class":81},[71,698,691],{"class":182},[71,700,701],{"class":222},"IsSubclassOf",[71,703,226],{"class":182},[71,705,706],{"class":172},"typeof",[71,708,226],{"class":182},[71,710,153],{"class":191},[71,712,713],{"class":182},"))) {\n",[71,715,717,720,723,725,727,730],{"class":73,"line":716},18,[71,718,719],{"class":191},"      MethodInfo",[71,721,722],{"class":182}," potentialMethod ",[71,724,101],{"class":81},[71,726,691],{"class":182},[71,728,729],{"class":222},"GetMethod",[71,731,732],{"class":182},"(methodName);\n",[71,734,736,739,742,744,746],{"class":73,"line":735},19,[71,737,738],{"class":172},"      if",[71,740,741],{"class":182}," (potentialMethod ",[71,743,682],{"class":81},[71,745,685],{"class":568},[71,747,244],{"class":182},[71,749,751,754,757,759,762,764,767,770],{"class":73,"line":750},20,[71,752,753],{"class":191},"        Controller",[71,755,756],{"class":182}," controller ",[71,758,101],{"class":81},[71,760,761],{"class":182}," (",[71,763,153],{"class":191},[71,765,766],{"class":182},") Activator.",[71,768,769],{"class":222},"CreateInstance",[71,771,772],{"class":182},"(potentialController, context);\n",[71,774,776,779,782,785,788],{"class":73,"line":775},21,[71,777,778],{"class":182},"        potentialMethod.",[71,780,781],{"class":222},"Invoke",[71,783,784],{"class":182},"(controller, ",[71,786,787],{"class":568},"null",[71,789,375],{"class":182},[71,791,793],{"class":73,"line":792},22,[71,794,795],{"class":182},"      }\n",[71,797,799],{"class":73,"line":798},23,[71,800,801],{"class":172},"      else\n",[71,803,805,808,810,812,814,817,820,822,824,827,829],{"class":73,"line":804},24,[71,806,807],{"class":182},"        context.",[71,809,358],{"class":256},[71,811,195],{"class":182},[71,813,363],{"class":222},[71,815,816],{"class":182},"(String.",[71,818,819],{"class":222},"Format",[71,821,226],{"class":182},[71,823,105],{"class":104},[71,825,826],{"class":108},"Method '{0}' not found on controller '{1}'",[71,828,105],{"class":104},[71,830,831],{"class":182},", methodName, controllerName));\n",[71,833,835],{"class":73,"line":834},25,[71,836,605],{"class":182},[71,838,840],{"class":73,"line":839},26,[71,841,842],{"class":172},"    else\n",[71,844,846,848,850,852,854,856,858,860,862,865,867],{"class":73,"line":845},27,[71,847,576],{"class":182},[71,849,358],{"class":256},[71,851,195],{"class":182},[71,853,363],{"class":222},[71,855,816],{"class":182},[71,857,819],{"class":222},[71,859,226],{"class":182},[71,861,105],{"class":104},[71,863,864],{"class":108},"Controller '{0}' not found",[71,866,105],{"class":104},[71,868,869],{"class":182},", controllerName));\n",[71,871,873],{"class":73,"line":872},28,[71,874,268],{"class":182},[71,876,878],{"class":73,"line":877},29,[71,879,213],{"emptyLinePlaceholder":212},[71,881,883,885,888],{"class":73,"line":882},30,[71,884,306],{"class":81},[71,886,887],{"class":343}," bool",[71,889,890],{"class":182}," IsReusable {\n",[71,892,894,897,900,903,906],{"class":73,"line":893},31,[71,895,896],{"class":343},"    get",[71,898,899],{"class":182}," { ",[71,901,902],{"class":172},"return",[71,904,905],{"class":568}," false",[71,907,908],{"class":182},"; }\n",[71,910,912],{"class":73,"line":911},32,[71,913,268],{"class":182},[71,915,917],{"class":73,"line":916},33,[71,918,274],{"class":182},[10,920,921],{},"That’s it!",[46,923,925],{"id":924},"limitations","Limitations",[10,927,928],{},"The controllers and methods are mapped at run-time using reflection. This would probably be too slow for production. Also it currently has to be in a top-level folder because I can’t figure out how to pass the HTTP request back to ASP.NET to try with the rest of the stack if we don’t have a matching controller\u002Fmethod.",[10,930,931],{},"One option might be to have no httpHandlers in the web.config and add the exact controller\u002Fmethod maps at build or run-time. This solves both the top-level problem and potentially the speed.",[10,933,934,935,938],{},"Another option to address just the speed of reflection would be to cache the path\u002Fmethod strings to the actual method and type so the only reflection would be the ",[41,936,937],{},"Activator.CreateInstance",". If that is slow then we could look at pooling the controller instances themselves.",[46,940,942],{"id":941},"going-forward","Going forward",[10,944,945],{},"Parameters for a method could be extracted and parsed from the query-string but they are currently ignored.",[10,947,948],{},"Response is raw output; we could do something very similar to rhtml.",[10,950,951],{},"I’m going to chat things over with the Subsonic team and see if we can come up with anything from here.",[10,953,954],{},[955,956,957],"em",{},"[)amien",[959,960,961],"style",{},"html pre.shiki code .sNvvj, html code.shiki .sNvvj{--shiki-default:#8DA101;--shiki-dark:#F8F8F2}html pre.shiki code .s9HRq, html code.shiki .s9HRq{--shiki-default:#F57D26;--shiki-dark:#FF79C6}html pre.shiki code .sr8dK, html code.shiki .sr8dK{--shiki-default:#DFA000;--shiki-default-font-style:inherit;--shiki-dark:#50FA7B;--shiki-dark-font-style:italic}html pre.shiki code .sciFF, html code.shiki .sciFF{--shiki-default:#8DA101;--shiki-dark:#E9F284}html pre.shiki code .sJQOs, html code.shiki .sJQOs{--shiki-default:#8DA101;--shiki-dark:#F1FA8C}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .smiwp, html code.shiki .smiwp{--shiki-default:#F85552;--shiki-dark:#FF79C6}html pre.shiki code .sPLAf, html code.shiki .sPLAf{--shiki-default:#3A94C5;--shiki-dark:#8BE9FD}html pre.shiki code .s6Vpi, html code.shiki .s6Vpi{--shiki-default:#5C6A72;--shiki-dark:#F8F8F2}html pre.shiki code .snuxY, html code.shiki .snuxY{--shiki-default:#3A94C5;--shiki-default-font-style:inherit;--shiki-dark:#8BE9FD;--shiki-dark-font-style:italic}html pre.shiki code .sS4Kt, html code.shiki .sS4Kt{--shiki-default:#8DA101;--shiki-dark:#50FA7B}html pre.shiki code .s7cAX, html code.shiki .s7cAX{--shiki-default:#5C6A72;--shiki-default-font-style:inherit;--shiki-dark:#FFB86C;--shiki-dark-font-style:italic}html pre.shiki code .sKO3f, html code.shiki .sKO3f{--shiki-default:#DF69BA;--shiki-default-font-style:inherit;--shiki-dark:#BD93F9;--shiki-dark-font-style:italic}html pre.shiki code .sSKRk, html code.shiki .sSKRk{--shiki-default:#35A77C;--shiki-dark:#F8F8F2}html pre.shiki code .stJs5, html code.shiki .stJs5{--shiki-default:#5C6A72;--shiki-default-font-style:inherit;--shiki-dark:#BD93F9;--shiki-dark-font-style:italic}html pre.shiki code .sXAHl, html code.shiki .sXAHl{--shiki-default:#3A94C5;--shiki-dark:#FF79C6}html pre.shiki code .sjYfO, html code.shiki .sjYfO{--shiki-default:#DF69BA;--shiki-default-font-style:inherit;--shiki-dark:#8BE9FD;--shiki-dark-font-style:italic}html pre.shiki code .sFDqs, html code.shiki .sFDqs{--shiki-default:#5C6A72;--shiki-dark:#F1FA8C}html pre.shiki code .s3Ipq, html code.shiki .s3Ipq{--shiki-default:#DF69BA;--shiki-dark:#BD93F9}",{"title":67,"searchDepth":88,"depth":88,"links":963},[964,965,966],{"id":48,"depth":88,"text":49},{"id":924,"depth":88,"text":925},{"id":941,"depth":88,"text":942},"Development","2007-07-26T01:06:00+00:00","Rob Conery has been putting together some great screen casts on SubSonic and his latest on generating controllers pointed out that ASP.NET doesn’t support the Rails-style http:\u002F\u002Fsite\u002F\u002Fcontroller\u002Fmethod style of execution.","[object Object]","md",null,false,{},"\u002Fblog\u002F2007\u002Frails-style-controllers-for-aspnet",{"title":5,"description":969},"blog\u002F2007\u002Frails-style-controllers-for-aspnet",[979,980,981],".NET","ASP.NET","C#","\u002Fblog\u002F2007\u002Frails-style-controllers-for-aspnet\u002F",746,"0AyxY_zW_mW6SeD1xzJwx8qPJl5xdx84dHjpStuxd04",[986,990,994],{"title":987,"date":988,"url":989},"Transactions in the MongoDB EF Core Provider","2025-10-25","\u002Fblog\u002F2025\u002Fmongodb-explicit-transactions\u002F",{"title":991,"date":992,"url":993},"Queryable Encryption with the MongoDB EF Core Provider","2025-09-22","\u002Fblog\u002F2025\u002Fmongodb-queryable-encryption\u002F",{"title":995,"date":996,"url":997},"Lazy Loading with EF Core Proxies","2025-04-02","\u002Fblog\u002F2025\u002Fef-proxies\u002F",[],1780900531651]