I'm experimenting with the documentation of http://www.restfulrouting.com/. When I open my routedug the links are like i want. But when I click the link i get a 404. I have the following structure
1. Login
1.1 Company (Area)
1.1.1 Departments
1.1.2 Contacts
1.1.1 Company info
1.2 Customer (Area)
//other information
My folder structure
Controllers (folder)
customers (folder)
AreasController.cs
CompanyController.cs
TestController.cs
AccountController.cs
Routes.cs
using System.Web.Routing;
using RestfulRouting;
using extranet.Controllers;
using extranet.Controllers.customers;
[assembly: WebActivator.PreApplicationStartMethod(typeof(extranet.Routes), "Start")]
namespace extranet
{
public class Routes : RouteSet
{
public override void Map(IMapper map)
{
map.DebugRoute("routedebug");
map.Resource<CompanyController>(comp => comp.Only("show"));
/*******************************
********COMPANYAREA*************
********************************/
map.Area<AreasController>("customer", area =>
{
area.Resource<TestController>();
area.Resource<CompanyController>();
});
}
public static void Start()
{
var routes = RouteTable.Routes;
routes.MapRoutes<Routes>();
}
}
}
CompanyController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using System.Web;
using System.Web.Mvc;
namespace extranet.Controllers
{
public class CompanyController : ApplicationController
{
//
// GET: /Company/
public ActionResult Index()
{
return View();
}
public ActionResult Show()
{
return View();
}
}
}
My question is when I go to {mysite}/customer/company --> I get the 404 page. When i got to {mysite}/company it shows me the page. What am I overseeing or where is my mistake? If I am missing some code here please tell me then I will place an edit.
Thanks in advance
Wow, just spend 4 hours figuring it out. Turns out i dragged the CompanyController from my controllers map to my customers class. Which means the namespace wasn't changed --> means link didn't recognize the controller.
I just had to add: namespace extranet.Controllers.Customers
Related
So we have a working ServiceStack service hosted inside a Windows Service using .Net 4.6.2, which uses a bunch of Fluent Validation validators.
We would like to port this to .Net Core. So I started to create cut down project just with a few of the features of our main app to see what the port to .Net Core would be like.
Most things are fine, such as
IOC
Routing
Hosting
Endpoint is working
The thing that does not seem to be correct is validation. To illustrate this I will walk through some existing .Net 4.6.2 code and then the .Net Core code. Where I have included the results for both
.NET 4.6.2 example
This is all good when using the full .Net 4.6.2 framework and the various ServiceStack Nuget packages.
For example I have this basic Dto (please ignore the strange name, long story not my choice)
using ServiceStack;
namespace .RiskStore.ApiModel.Analysis
{
[Route("/analysis/run", "POST")]
public class AnalysisRunRequest : BaseRequest, IReturn<AnalysisRunResponse>
{
public AnalysisPart Analysis { get; set; }
}
}
Where we have this base class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace .RiskStore.ApiModel
{
public abstract class BaseRequest
{
public string CreatedBy { get; set;}
}
}
And we have this validator (we have way more than this working in .Net 4.6.2 app, this is just to show differences between full .Net and .Net Core which we will see in a minute)
using .RiskStore.ApiModel.Analysis;
using ServiceStack.FluentValidation;
namespace .RiskStore.ApiServer.Validators.Analysis
{
public class AnalysisRunRequestValidator : AbstractValidator<AnalysisRunRequest>
{
public AnalysisRunRequestValidator(AnalysisPartValidator analysisPartValidator)
{
RuleFor(analysis => analysis.CreatedBy)
.Must(HaveGoodCreatedBy)
.WithMessage("CreatedBy MUST be 'sbarber'")
.WithErrorCode(ErrorCodes.ValidationErrorCode);
}
private bool HaveGoodCreatedBy(AnalysisRunRequest analysisRunRequest, string createdBy)
{
return createdBy == "sbarber";
}
}
}
And here is my host file for this service
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Funq;
using .RiskStore.ApiModel.Analysis;
using .RiskStore.ApiModel.Analysis.Results;
using .RiskStore.ApiServer.Api.Analysis;
using .RiskStore.ApiServer.Exceptions;
using .RiskStore.ApiServer.IOC;
using .RiskStore.ApiServer.Services;
using .RiskStore.ApiServer.Services.Results;
using .RiskStore.ApiServer.Validators.Analysis;
using .RiskStore.ApiServer.Validators.Analysis.Results;
using .RiskStore.DataAccess.AnalysisRun.Repositories.Results;
using .RiskStore.DataAccess.AnalysisRun.Repositories.Search;
using .RiskStore.DataAccess.AnalysisRun.Repositories.Validation;
using .RiskStore.DataAccess.Configuration;
using .RiskStore.DataAccess.Connectivity;
using .RiskStore.DataAccess.Ingestion.Repositories.EventSet;
using .RiskStore.DataAccess.JobLog.Repositories;
using .RiskStore.DataAccess.StaticData.Repositories;
using .RiskStore.DataAccess.UnitOfWork;
using .RiskStore.Toolkit.Configuration;
using .RiskStore.Toolkit.Jobs.Repositories;
using .RiskStore.Toolkit.Storage;
using .RiskStore.Toolkit.Utils;
using .Toolkit;
using .Toolkit.Configuration;
using .Toolkit.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ServiceStack;
using ServiceStack.Text;
using ServiceStack.Validation;
namespace .RiskStore.ApiServer.Api
{
public class ApiServerHttpHost : AppHostHttpListenerBase
{
private readonly ILogger _log = Log.ForContext<ApiServerHttpHost>();
public static string RoutePrefix => "analysisapi";
/// <summary>
/// Base constructor requires a Name and Assembly where web service implementation is located
/// </summary>
public ApiServerHttpHost()
: base(typeof(ApiServerHttpHost).FullName, typeof(AnalysisServiceStackService).Assembly)
{
_log.Debug("ApiServerHttpHost constructed");
}
public override void SetConfig(HostConfig config)
{
base.SetConfig(config);
JsConfig.TreatEnumAsInteger = true;
JsConfig.EmitCamelCaseNames = true;
JsConfig.IncludeNullValues = true;
JsConfig.AlwaysUseUtc = true;
JsConfig<Guid>.SerializeFn = guid => guid.ToString();
JsConfig<Guid>.DeSerializeFn = Guid.Parse;
config.HandlerFactoryPath = RoutePrefix;
var exceptionMappings = new Dictionary<Type, int>
{
{typeof(JobServiceException), 400},
{typeof(NullReferenceException), 400},
};
config.MapExceptionToStatusCode = exceptionMappings;
_log.Debug("ApiServerHttpHost SetConfig ok");
}
/// <summary>
/// Application specific configuration
/// This method should initialize any IoC resources utilized by your web service classes.
/// </summary>
public override void Configure(Container container)
{
//Config examples
//this.Plugins.Add(new PostmanFeature());
//this.Plugins.Add(new CorsFeature());
Plugins.Add(new ValidationFeature());
container.RegisterValidators(typeof(AnalysisRunRequestValidator).Assembly);
.......
.......
.......
.......
container.Register<AnalysisPartValidator>(c => new AnalysisPartValidator(
c.Resolve<AnalysisDealPartLinkingModelEventSetValidator>(),
c.Resolve<AnalysisOutputSettingsPartValidMetaRisksValidator>(),
c.Resolve<AnalysisOutputSettingsGroupPartValidMetaRisksValidator>(),
c.Resolve<AnalysisDealPartCollectionValidator>(),
c.Resolve<AnalysisPortfolioPartCollectionValidator>(),
c.Resolve<UniqueCombinedOutputSettingsPropertiesValidator>()))
.ReusedWithin(ReuseScope.None);
container.Register<AnalysisRunRequestValidator>(c => new AnalysisRunRequestValidator(c.Resolve<AnalysisPartValidator>()))
.ReusedWithin(ReuseScope.None);
_log.Debug("ApiServerHttpHost Configure ok");
SetConfig(new HostConfig
{
DefaultContentType = MimeTypes.Json
});
}}
}
So I then hit this endpoint with this JSON
{
"Analysis": {
//Not important for discussion
//Not important for discussion
//Not important for discussion
//Not important for discussion
},
"CreatedBy": "frank"
}
And I get this response in PostMan tool (which I was expecting)
So that's all good.
.NET Core example
So now lets see what its like in .Net core example.
Lets start with the request dto
using System;
namespace ServiceStack.Demo.Model.Core
{
[Route("/analysis/run", "POST")]
public class AnalysisRunRequest : BaseRequest, IReturn<AnalysisRunResponse>
{
public AnalysisDto Analysis { get; set; }
}
}
Which uses this base request object
using System;
using System.Collections.Generic;
using System.Text;
namespace ServiceStack.Demo.Model.Core
{
public abstract class BaseRequest
{
public string CreatedBy { get; set; }
}
}
And here is the same validator we used from .NET 4.6.2 example, but in my .Net Core code instead
using System;
using System.Collections.Generic;
using System.Text;
using ServiceStack.Demo.Model.Core;
using ServiceStack.FluentValidation;
namespace ServiceStack.Demo.Core.Validators
{
public class AnalysisRunRequestValidator : AbstractValidator<AnalysisRunRequest>
{
public AnalysisRunRequestValidator(AnalysisDtoValidator analysisDtoValidator)
{
RuleFor(analysis => analysis.CreatedBy)
.Must(HaveGoodCreatedBy)
.WithMessage("CreatedBy MUST be 'sbarber'")
.WithErrorCode(ErrorCodes.ValidationErrorCode);
}
private bool HaveGoodCreatedBy(AnalysisRunRequest analysisRunRequest, string createdBy)
{
return createdBy == "sbarber";
}
}
}
And here is my host code for .Net core example
using System;
using System.Collections.Generic;
using System.Text;
using Funq;
using ServiceStack.Demo.Core.Api.Analysis;
using ServiceStack.Demo.Core.IOC;
using ServiceStack.Demo.Core.Services;
using ServiceStack.Demo.Core.Validators;
using ServiceStack.Text;
using ServiceStack.Validation;
namespace ServiceStack.Demo.Core.Api
{
public class ApiServerHttpHost : AppHostBase
{
public static string RoutePrefix => "analysisapi";
public ApiServerHttpHost()
: base(typeof(ApiServerHttpHost).FullName, typeof(AnalysisServiceStackService).GetAssembly())
{
Console.WriteLine("ApiServerHttpHost constructed");
}
public override void SetConfig(HostConfig config)
{
base.SetConfig(config);
JsConfig.TreatEnumAsInteger = true;
JsConfig.EmitCamelCaseNames = true;
JsConfig.IncludeNullValues = true;
JsConfig.AlwaysUseUtc = true;
JsConfig<Guid>.SerializeFn = guid => guid.ToString();
JsConfig<Guid>.DeSerializeFn = Guid.Parse;
config.HandlerFactoryPath = RoutePrefix;
var exceptionMappings = new Dictionary<Type, int>
{
{typeof(NullReferenceException), 400},
};
config.MapExceptionToStatusCode = exceptionMappings;
Console.WriteLine("ApiServerHttpHost SetConfig ok");
}
public override void Configure(Container container)
{
//Config examples
//this.Plugins.Add(new PostmanFeature());
//this.Plugins.Add(new CorsFeature());
Plugins.Add(new ValidationFeature());
container.RegisterValidators(typeof(ApiServerHttpHost).GetAssembly());
container.RegisterAutoWiredAs<DateProvider, IDateProvider>()
.ReusedWithin(ReuseScope.Container);
container.RegisterAutoWiredAs<FakeRepository, IFakeRepository>()
.ReusedWithin(ReuseScope.Container);
container.Register<LifetimeScopeManager>(cont => new LifetimeScopeManager(cont))
.ReusedWithin(ReuseScope.Hierarchy);
container.Register<DummySettingsPropertiesValidator>(c => new DummySettingsPropertiesValidator(c.Resolve<LifetimeScopeManager>()))
.ReusedWithin(ReuseScope.None);
container.Register<AnalysisDtoValidator>(c => new AnalysisDtoValidator(
c.Resolve<DummySettingsPropertiesValidator>()))
.ReusedWithin(ReuseScope.None);
container.Register<AnalysisRunRequestValidator>(c => new AnalysisRunRequestValidator(c.Resolve<AnalysisDtoValidator>()))
.ReusedWithin(ReuseScope.None);
SetConfig(new HostConfig
{
DefaultContentType = MimeTypes.Json
});
}
}
}
And this is me trying to now hit the .Net Core endpoint with the same bad JSON payload as demonstrated above with the .Net 4.6.2 example, which gave correct Http response (i.e included error that I was expecting in response)
Anyway here is payload being sent to .Net Core endpoint
{
"Analysis": {
//Not important for discussion
//Not important for discussion
//Not important for discussion
//Not important for discussion
},
"CreatedBy": "frank"
}
Where we can see that we are getting into the .Net Core example validator code just fine
But this time I get a very different Http response (one that I was not expecting at all). I get this
It can be seen that we do indeed get the correct Status code of "400" (failed) which is good. But we DO NOT get anything about the validation failure at all.
I was expecting this to give me the same http response as the original .Net 4.6.2 example above.
But what I seem to be getting back is the JSON representing the AnalysisRunResponse. Which looks like this
using System;
using System.Collections.Generic;
using System.Text;
namespace ServiceStack.Demo.Model.Core
{
public class AnalysisRunResponse : BaseResponse
{
public Guid AnalysisUid { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace ServiceStack.Demo.Model.Core
{
public abstract class BaseResponse
{
public ResponseStatus ResponseStatus { get; set; }
}
}
I thought the way ServiceStack works (in fact that is how it works for ALL our existing .Net 4.6.2 code) is that the validation is done first, if AND ONLY if it passes validation is the actual route code run
But this .Net core example seems to not work like that.
I have a break point set in Visual Studio for the actual route and Console.WriteLine(..) but that is never hit and I never see the result of the Console.WriteLine(..)
What am I doing wrong?
This doesn't seem to any longer an issue with the latest v5 of ServiceStack that's now available on MyGet.
As sending this request:
Is returning the expected response:
The .NET Core packages are merged with the main packages in ServiceStack v5 so you'll need to remove the .Core prefix to download them, i.e:
<PackageReference Include="ServiceStack" Version="5.*" />
<PackageReference Include="ServiceStack.Server" Version="5.*" />
You'll also need to add ServiceStack's MyGet feed to fetch the latest ServiceStack v5 NuGet packages which you can do by adding this NuGet.config in the same folder as your .sln:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="ServiceStack MyGet feed" value="https://www.myget.org/F/servicestack" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration>
After using Android layout this.SetContentView(Resource.Layout.Main), and LoadApplication(new App()), I could not see Xamarin.Forms MainPage.xaml. I tried to remove the Linear Layout, but it just removing items inside them, not the form itself. It seems like SetContentView blocking the Xamarin.Forms. So,
Here is MainActivity.cs:
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Text.Method;
using Android.Widget;
using Auth0.OidcClient;
using IdentityModel.OidcClient;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xamarin.Forms;
namespace IndoFellowship.Droid {
// Define App icon and name
[Activity(
Label = "Indo App",
MainLauncher = true,
Icon = "#drawable/icon",
LaunchMode = LaunchMode.SingleTask)
]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity {
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
// Showing layout that I set
SetContentView(Resource.Layout.Main);
// Do login
// Some codes
// Done processing on Android, I need to load Xamarin.Forms
LinearLayout mainLayout = (LinearLayout)FindViewById(Resource.Id.mainLayoutID);
mainLayout.RemoveAllViews();
// Load App
LoadApplication(new App());
}
}
}
Main.axml on Resources/values/
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainLayoutID"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
// Some layout here..
</LinearLayout>
and my App.xaml.cs (Xamarin)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xamarin.Forms;
namespace IndoFellowship {
public partial class App : Application {
public static string AppName { get; set; }
public App() {
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
protected override void OnStart() {
// Handle when your app starts
}
protected override void OnSleep() {
// Handle when your app sleeps
}
protected override void OnResume() {
// Handle when your app resumes
}
}
}
MainPage.xaml.cs (Xamarin)
using Auth0.OidcClient;
using IdentityModel.OidcClient;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Auth;
using Xamarin.Forms;
namespace IndoFellowship
{
public partial class MainPage : ContentPage {
public MainPage()
{
InitializeComponent();
var browser = new WebView();
browser.Source = "http://xamarin.com";
Content = browser;
}
}
}
Over here I should seeing xamarin.com webView, but my Android just went blank. It seems like Xamarin.Forms not showing at all and I am still on Xamarin.Android. If I took SetContentView, I can see the forms rendered perfectly, but I could not process what I need to do on Android.
What I need to do to properly load Xamarin Forms from MainActivity?
Why layout not removed?
Thank you.
I found my solution by using StartActivity instead of LoadApplication.
By creating a second activity:
XamarinForms.cs this activity load the app()
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace IndoFellowship.Droid {
[Activity(Label = "XamarinForm")]
public class XamarinForm : Xamarin.Forms.Platform.Android.FormsApplicationActivity {
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
}
}
}
MainActivity.cs instead of LoadApplication here, I am calling the second activity instead
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Text.Method;
using Android.Widget;
using Auth0.OidcClient;
using IdentityModel.OidcClient;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xamarin.Forms;
namespace IndoFellowship.Droid {
// Define App icon and name
[Activity(
Label = "Indo App",
MainLauncher = true,
Icon = "#drawable/icon",
LaunchMode = LaunchMode.SingleTask)
]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity {
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
// Showing layout that I set
SetContentView(Resource.Layout.Main);
// Do login
// Some codes
// Done processing on Android, I need to load Xamarin.Forms
LinearLayout mainLayout = (LinearLayout)FindViewById(Resource.Id.mainLayoutID);
mainLayout.RemoveAllViews();
// Load App
StartActivity(typeof(XamarinForms));
}
}
}
May be this is not a best design since now I have two activities. Please let me know if you know better way to accomplish this. Thank you.
I am trying to add an option under Actions in Acumatica on the Transactions screen CA304000. See below what I am trying to achieve:
using System;
using System.Collections;
using System.Collections.Generic;
using PX.Data;
using PX.Objects.Common;
using PX.Objects.AP;
using PX.Objects.CM;
using PX.Objects.CS;
using PX.Objects.GL;
using PX.Objects.IN;
using PX.Objects.TX;
using PX.Objects.EP;
using PX.Objects.CR;
using Avalara.AvaTax.Adapter;
using Avalara.AvaTax.Adapter.TaxService;
using AvaAddress = Avalara.AvaTax.Adapter.AddressService;
using AvaMessage = Avalara.AvaTax.Adapter.Message;
using CRLocation = PX.Objects.CR.Standalone.Location;
using PX.Objects;
using PX.Objects.CA;
namespace PX.Objects.CA
{
public class CATranEntry_Extension:PXGraphExtension<CATranEntry>
{
#region Event Handlers
public override void Initialize()
{
Base.action.AddMenuAction(ShowURL);
}
public PXAction<CAAdj> ShowURL;
[PXUIField(DisplayName = "Phieu Thu")]
[PXButton]
protected virtual void showURL()
{
CAAdj doc = Base.Document.Current;
if (doc.RefNbr != null)
{
throw new PXReportRequiredException(doc, "TNCA6401", null);
}
}
#endregion
}
}
This is however telling me that there is ('PX.Objects.CA.CATranEntry' does not contain a definition for 'Document' and no extension method 'Document' accepting a first argument of type 'PX.Objects.CA.CATranEntry' could be found) twice.
this TNCA6401 only have one paramenter Reference Number. Please be specific (Image is the best). I'm Noob. Thanks you.
You should be working with CAAdjRecords data view not Document.
CAAdj doc = Base.Document.Current;
should be CAAdj doc = Base.CAAdjRecords.Current
And Reference Nbr. is tied to AdjRefNbr field.
You could use Customization -> Inspect Element to identify screen is working with which Graph, Data View, DAC and DAC field.
The code provided in the book Pro ASP.NET MVC 5 from Apress in chapter 16 (Routing Incoming URLs) The example is about legacy urls. Next i will put the code samples for the custom route, routeconfig, controller and view.
LegacyRoute.cs
using System;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace UrlsAndRoutes.Infrastructure
{
public class LegacyRoute : RouteBase
{
private string[] urls;
public LegacyRoute(params string[] targetUrls)
{
urls = targetUrls;
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
RouteData result = null;
string requestedURL = httpContext.Request.AppRelativeCurrentExecutionFilePath;
if (urls.Contains(requestedURL, StringComparer.OrdinalIgnoreCase))
{
result = new RouteData(this, new MvcRouteHandler());
result.Values.Add("controller", "Legacy");
result.Values.Add("action", "GetLegacyURL");
result.Values.Add("legacyURL", requestedURL);
}
return result;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
VirtualPathData result = null;
if (values.ContainsKey("legacyURL") && urls.Contains((string)values["legacyURL"], StringComparer.OrdinalIgnoreCase))
{
result = new VirtualPathData(this, new UrlHelper(requestContext).Content((string)values["legacyURL"]).Substring(1));
}
return result;
}
}
}
RouteConfig.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Mvc.Routing.Constraints;
using UrlsAndRoutes.Infrastructure;
namespace UrlsAndRoutes
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapMvcAttributeRoutes();
//routes.MapRoute("NewRoute", "App/Do{action}", new { controller = "Home", id = UrlParameter.Optional });
//routes.Add(new Route("SayHello", new CustomRouteHandler()));
routes.Add(new LegacyRoute("~/articles/Windows_3.1_Overview.html", "~/old/.NET_1.0_Class_Library"));
routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" });
routes.MapRoute("MyOtherRoute", "App/{action}", new { controller = "Home" });
}
}
}
LegacyController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace UrlsAndRoutes.Controllers
{
public class LegacyController : Controller
{
public ActionResult GetLegacyURL(string legacyURL)
{
return View((object)legacyURL);
}
}
}
GetLegacyURL.cshtml
#model string
#{
ViewBag.Title = "GetLegacyURL";
Layout = null;
}
<h2>GetLegacyURL</h2>
The URL requested was: #Model
I can't figure how to put it work. I always get 404 error (http://my.machine/articles/Windows_3.1_Overview.html). The method in the GetRouteData in LegacyRoute.cs is never called. If I remove the . from the URL the code works fine. Can anyone give some advice or help?
It is strange that no one are complaining that the code doesn't work.
Page 445 provides the solution. You need to edit IIS Express settings.
Right click on the IIS Express icon on the taskbar while the application is running -> Show all applications -> Click on the site you want to configure -> Click on the configuration file
Search for System.Web.Routing.UrlRoutingModule
Remove the preCondition attribute value so the line becomes <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
Restart the application and you are ready.
routes.MapMvcAttributeRoutes();
routes.Add(new LegacyRoute("~/articles/Windows_3.1_Overview.html/",
"~/old/.NET_1.0_Class_Library/"));
routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home" ,action="index" });
routes.MapRoute("MyOtherRoute", "App/{action}", new { controller = "Home" });
Try with above code , this should be worked.
Malinda Sanjaka
I have a UserControl which I have added to my web.config
<add tagPrefix="BCF" src="~/controls/MyMessageBox.ascx" tagName="error"/>
and added to my master page
<BCF:error ID="BCError" runat="server" Visible="false" />
Now I need to be able to reference this control AND its public properties from all child pages that use that masterpage. I did this is my BasePage OnLoad event
public UserControl BCError;
BCError = (UserControl)Master.FindControl("BCError");
Problem is, although I can do this in the .aspx page
BCError.Visible = true;
I cannot reference any of the Controls properties I have put in? Such as ShowError .. If I do
BCError.ShowError = "Error Message";
I just get an error saying
'System.Web.UI.UserControl' does not contain a definition for 'ShowInfo' and no extension method 'ShowInfo'
Can you please point me in the right direction!
This is the code for the user control... I can use the properties in the masterpage code behind (And in a page if I put the control directly into it) but cannot use them in the child page code behind?? It doesn't even show the properties or wrapper methods in the intellisense?
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
public partial class MyMessageBox : System.Web.UI.UserControl
{
#region Properties
public bool ShowCloseButton { get; set; }
#endregion
#region Load
protected void Page_Load(object sender, EventArgs e)
{
if (ShowCloseButton)
CloseButton.Attributes.Add("onclick", "document.getElementById('" + MessageBox.ClientID + "').style.display = 'none'");
}
#endregion
#region Wrapper methods
public void ShowError(string message)
{
Show(MessageType.Error, message);
}
public void ShowInfo(string message)
{
Show(MessageType.Info, message);
}
public void ShowSuccess(string message)
{
Show(MessageType.Success, message);
}
public void ShowWarning(string message)
{
Show(MessageType.Warning, message);
}
#endregion
#region Show control
public void Show(MessageType messageType, string message)
{
CloseButton.Visible = ShowCloseButton;
litMessage.Text = message;
MessageBox.CssClass = messageType.ToString().ToLower();
this.Visible = true;
}
#endregion
#region Enum
public enum MessageType
{
Error = 1,
Info = 2,
Success = 3,
Warning = 4
}
#endregion
}
Ok I think I reproduced roughly what your describing and I deleted my original answer cause it was way off.
What I found is that when you want a content page to reference a user control being used in a master page and the control is accesible and what not, you will get an error indicating that you need to reference a specific assembly, and then you get errors indicating that no Method exists of type such and such.
By adding the Register page directive on the child page to the user control resolved this issue. I reproduced this even with the control defined in the web.config or on the page. In both cases I still had to explicitly add a Register on the content page.
This doesn't make sense to me but it allowed my code to compile and work. Give it a shot let me know.
Once you do this you can reference the control like
this.Master.MessageBox.ShowInfo();
This assumes that you have a public property called MessageBox on the Master Page.
Edit
I've also found that this works much better if you register the control on both the master and the content page and not use the web.config.
Edit
If you don't want your child page to reference the user control your other option is expose methods on the master page like ShowInfo() which would delegate to the user control.
You need to declare it as your control type to access it's properties.
public MyMessageBox BCError;
BCError = (MyMessageBox )Master.FindControl("BCError");
Try using this in the pages that inherit from your master page:
<%# MasterType VirtualPath="~/MasterPageName.Master" %>