{"id":20299763,"url":"https://github.com/ontopiccms/ontopic-mvc","last_synced_at":"2026-07-01T03:32:36.830Z","repository":{"id":101142894,"uuid":"230078525","full_name":"OnTopicCMS/OnTopic-MVC","owner":"OnTopicCMS","description":"Library for deploying the OnTopic CMS to an ASP.NET MVC Framework based website.","archived":false,"fork":false,"pushed_at":"2019-12-29T07:49:19.000Z","size":236,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-04T06:24:36.205Z","etag":null,"topics":["asp","asp-net","asp-net-mvc","cms","content-management","content-management-system","ignia","mvc","mvc-framework","net-mvc","ontopic","ontopic-library","presentation-layer","razor-class-library","web-application"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OnTopicCMS.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-25T09:31:07.000Z","updated_at":"2023-06-02T11:13:00.000Z","dependencies_parsed_at":null,"dependency_job_id":"617dbf5c-1315-47a0-908e-797b1cabf643","html_url":"https://github.com/OnTopicCMS/OnTopic-MVC","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/OnTopicCMS/OnTopic-MVC","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OnTopicCMS%2FOnTopic-MVC","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OnTopicCMS%2FOnTopic-MVC/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OnTopicCMS%2FOnTopic-MVC/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OnTopicCMS%2FOnTopic-MVC/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OnTopicCMS","download_url":"https://codeload.github.com/OnTopicCMS/OnTopic-MVC/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OnTopicCMS%2FOnTopic-MVC/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34992071,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-01T02:00:05.325Z","response_time":130,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asp","asp-net","asp-net-mvc","cms","content-management","content-management-system","ignia","mvc","mvc-framework","net-mvc","ontopic","ontopic-library","presentation-layer","razor-class-library","web-application"],"created_at":"2024-11-14T16:16:13.383Z","updated_at":"2026-07-01T03:32:36.809Z","avatar_url":"https://github.com/OnTopicCMS.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿# `Ignia.Topics.Web.Mvc`\nThe `Ignia.Topics.Web.Mvc` assembly provides an implementation of OnTopic for use with the ASP.NET MVC 5.x Framework.\n\n### Contents\n- [Components](#components)\n- [Controllers](#controllers)\n- [View Conventions](#view-conventions)\n  - [View Matching](#view-matching)\n  - [View Locations](#view-locations)\n  - [Example](#example)\n- [Configuration](#configuration)\n  - [Application](#application)\n  - [Route Configuration](#route-configuration)\n  - [Controller Factory](#controller-factory)\n\n## Components\nThere are three key components at the heart of the MVC implementation.\n- **`MvcTopicRoutingService`**: This is a concrete implementation of the `ITopicRoutingService` which accepts contextual information about a given request (in this case, the URL and routing data) and then uses it to retrieve the current `Topic` from an `ITopicRepository`.\n- **`TopicController`**: This is a default controller instance that can be used for _any_ topic path. It will automatically validate that the `Topic` exists, that it is not disabled (`IsDisabled`), and will honor any redirects (e.g., if the `Url` attribute is filled out). Otherwise, it will return `TopicViewResult` based on a view model, view name, and content type.\n- **`TopicViewEngine`**: The `TopicViewEngine` is called every time a view is requested. It works in conjunction with `TopicViewResult` to identify matching MVC views based on predetermined locations and conventions. These are discussed below.\n\n## Controllers\nThere are six main controllers that ship with the MVC implementation. In addition to the core **`TopicController`**, these include the following ancillary controllers:\n- **`ErrorControllerBase\u003cT\u003e`**: Provides support for `Error`, `NotFound`, and `InternalServer` actions. Can accept any `IPageTopicViewModel` as a generic argument; that will be used as the view model.\n- **`FallbackController`**: Used in a [Controller Factory](#controller-factory) as a fallback, in case no other controllers can accept the request. Simply returns a `NotFoundResult` with a predefined message.\n- **`LayoutControllerBase\u003cT\u003e`**: Provides support for a navigation menu by automatically mapping the top three tiers of the current namespace (e.g., `Web`, its children, and grandchildren). Can accept any `INavigationTopicViewModel` as a generic argument; that will be used as the view model for each mapped instance.\n- **`RedirectController`**: Provides a single `Redirect` action which can be bound to a route such as `/Topic/{ID}/`; this provides support for permanent URLs that are independent of the `GetWebPath()`.\n- **`SitemapController`**: Provides a single `Sitemap` action which returns a reference to the `ITopicRepository`, thus allowing a sitemap view to recurse over the entire Topic graph, including all attributes.\n\n\u003e **Note:** There is not a practical way for MVC to provide routing for generic controllers. As such, these _must_ be subclassed by each implementation. The derived controller needn't do anything outside of provide a specific type reference to the generic base.\n\n## View Conventions\nBy default, OnTopic matches views based on the current topic's `ContentType` and, if available, `View`.\n\n### View Matching\nThere are multiple ways for a view to be set. The `TopicViewResult` will automatically evaluate views based on the following locations. The first one to match a valid view name is selected.\n- **`?View=`** query string parameter (e.g., `?View=Accordion`)\n- **`Accept`** headers (e.g., `Accept=application/json`); will treat the segment after the `/` as a possible view name\n- **`View`** attribute (i.e., `topic.View`)\n- **`ContentType`** attribute (i.e., `topic.ContentType`)\n\n### View Locations\nFor each of the above [View Matching](#view-matching) rules, the `TopicViewEngine` will search the following locations for a matching view:\n- `~/Views/{ContentType}/{View}.cshtml`\n- `~/Views/ContentTypes/{ContentType}.{View}.cshtml`\n- `~/Views/ContentTypes/{ContentType}.cshtml`\n- `~/Views/Shared/{View}.cshtml`\n\n\u003e *Note:* After searching each of these locations for each of the [View Matching](#view-matching) rules, control will be handed over to the [`RazorViewEngine`](https://msdn.microsoft.com/en-us/library/system.web.mvc.razorviewengine%28v=vs.118%29.aspx?f=255\u0026MSPPError=-2147217396), which will search the out-of-the-box default locations for ASP.NET MVC.\n\n### Example\nIf the `topic.ContentType` is `ContentList` and the `Accept` header is `application/json` then the `TopicViewResult` and `TopicViewEngine` would coordinate to search the following paths:\n- `~/Views/ContentList/JSON.cshtml`\n- `~/Views/ContentTypes/ContentList.JSON.cshtml`\n- `~/Views/ContentTypes/JSON.cshtml`\n- `~/Views/Shared/JSON.cshtml`\n\nIf no match is found, then the next `Accept` header will be searched. Eventually, if no match can be found on the various [View Matching](#view-matching) rules, then the following will be searched:\n\n- `~/Views/ContentList/ContentList.cshtml`\n- `~/Views/ContentTypes/ContentList.ContentList.cshtml`\n- `~/Views/ContentTypes/ContentList.cshtml`\n- `~/Views/Shared/ContentList.cshtml`\n\n## Configuration\n\n### Application\nIn the `global.asax.cs`, the following components should be registered under the `Application_Start` event handler:\n```\nControllerBuilder.Current.SetControllerFactory(new OrganizationNameControllerFactory());\nViewEngines.Engines.Insert(0, new TopicViewEngine());\n```\n\u003e *Note:* The controller factory name is arbitrary, and should follow the conventions appropriate for the site. Ignia typically uses `{OrganizationName}ControllerFactory` (e.g., `IgniaControllerFactory`), but OnTopic doesn't need to know or care what the name is; that is between your application and the ASP.NET MVC Framework.\n\n### Route Configuration\nWhen registering routes via `RouteConfig.RegisterRoutes()` (typically via the `RouteConfig` class), register a route for any OnTopic routes:\n```\nroutes.MapRoute(\n  name: \"WebTopics\",\n  url: \"Web/{*path}\",\n  defaults: new { controller = \"Topic\", action = \"Index\", id = UrlParameter.Optional, rootTopic = \"Web\" }\n);\n```\n\u003e *Note:* Because OnTopic relies on wildcard pathnames, a new route should be configured for every root namespace (e.g., `/Web`). While it's possible to configure OnTopic to evaluate _all_ paths, this makes it difficult to delegate control to other controllers and handlers, when necessary.\n\n### Controller Factory\nAs OnTopic relies on constructor injection, the application must be configured in a **Composition Root**—in the case of ASP.NET MVC, that means a custom controller factory. The basic structure of this might look like:\n```\nvar connectionString            = ConfigurationManager.ConnectionStrings[\"OnTopic\"].ConnectionString;\nvar sqlTopicRepository          = new SqlTopicRepository(connectionString);\nvar cachedTopicRepository       = new CachedTopicRepository(sqlTopicRepository);\nvar topicViewModelLookupService = new TopicViewModelLookupService();\nvar topicMappingService         = new TopicMappingService(cachedTopicRepository, topicViewModelLookupService);\n\nvar mvcTopicRoutingService      = new MvcTopicRoutingService(\n  cachedTopicRepository,\n  requestContext.HttpContext.Request.Url,\n  requestContext.RouteData\n);\n\nswitch (controllerType.Name) {\n\n  case nameof(TopicController):\n    return new TopicController(sqlTopicRepository, mvcTopicRoutingService, topicMappingService);\n\n  case default:\n    return base.GetControllerInstance(requestContext, controllerType);\n\n}\n\n```\nFor a complete reference template, including the ancillary controllers, see the [`OrganizationNameControllerFactory.cs`](https://gist.github.com/JeremyCaney/6ba4bb0465b7dd1992a7ffdaa1ebf813) Gist.\n\n\u003e *Note:* The default `TopicController` will automatically identify the current topic (based on e.g. the URL), map the current topic to a corresponding view model (based on [the `TopicMappingService` conventions](../Ignia.Topics/Mapping/)), and then return a corresponding view (based on the [view conventions](#view-conventions)). For most applications, this is enough. If custom mapping rules or additional presentation logic are needed, however, implementors can subclass `TopicController`.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fontopiccms%2Fontopic-mvc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fontopiccms%2Fontopic-mvc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fontopiccms%2Fontopic-mvc/lists"}