diff --git a/CHANGELOG.md b/CHANGELOG.md
index e75f8a6..fbded91 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
+### Added
+
+- Allow `TypeContractorIgnore` to be used on controller methods
+
## [0.20.0] - 2026-05-30
### Added
diff --git a/README.md b/README.md
index 17ff748..4227fb4 100644
--- a/README.md
+++ b/README.md
@@ -279,7 +279,8 @@ Available annotations:
generated, you can annotate that controller using `TypeContractorIgnore`
and it will be automatically skipped.
- Also works on properties that shouldn't be included in generated DTOs.
+ Also works on properties that shouldn't be included in generated DTOs,
+ or on endpoints in a controller if you only want some of the endpoints.
* `TypeContractorName`:
If you have a badly named controller that you can't rename,
you want something custom, or just don't like the default naming
diff --git a/TypeContractor.Annotations/TypeContractorIgnoreAttribute.cs b/TypeContractor.Annotations/TypeContractorIgnoreAttribute.cs
index f520890..6762c60 100644
--- a/TypeContractor.Annotations/TypeContractorIgnoreAttribute.cs
+++ b/TypeContractor.Annotations/TypeContractorIgnoreAttribute.cs
@@ -6,8 +6,12 @@ namespace TypeContractor.Annotations
/// Tells TypeContractor to ignore the target when generating TypeScript.
/// For example a controller that serves static assets for HTML templates.
/// Can also be used for properties that don't need to be exposed.
+ ///
+ /// When generating API clients, a single endpoint can be ignored using
+ /// this attribute.
+ ///
///
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class TypeContractorIgnoreAttribute : Attribute
{
}
diff --git a/TypeContractor.Tests/Helpers/ApiHelpersTests.cs b/TypeContractor.Tests/Helpers/ApiHelpersTests.cs
index 3fc4afc..b0cae8f 100644
--- a/TypeContractor.Tests/Helpers/ApiHelpersTests.cs
+++ b/TypeContractor.Tests/Helpers/ApiHelpersTests.cs
@@ -60,6 +60,19 @@ public void BuildApiEndpoint_Generates_Name()
endpoint.First().Name.Should().Be("overloadEndpoint");
}
+ [Fact]
+ public void BuildApiEndpoint_Skips_Ignored_Methods()
+ {
+ // Arrange
+ var endpointMethod = typeof(LegacyController).GetMethod(nameof(LegacyController.NothingToSeeHere), [typeof(CancellationToken)])!;
+
+ // Act
+ var endpoint = ApiHelpers.BuildApiEndpoint(endpointMethod);
+
+ // Assert
+ endpoint.Should().BeEmpty();
+ }
+
[TypeContractorIgnore]
internal class IgnoredController : ControllerBase { }
@@ -72,6 +85,10 @@ internal class LegacyController : ControllerBase
[HttpGet("other-route")]
public ActionResult OverloadEndpoint(CancellationToken cancellationToken) => NotFound();
+
+ [HttpPatch("third-route")]
+ [TypeContractorIgnore]
+ public ActionResult NothingToSeeHere(CancellationToken cancellationToken) => NotFound();
}
[TypeContractorName("RenamedApi")]
diff --git a/TypeContractor/Helpers/ApiHelpers.cs b/TypeContractor/Helpers/ApiHelpers.cs
index 8736367..0b95e04 100644
--- a/TypeContractor/Helpers/ApiHelpers.cs
+++ b/TypeContractor/Helpers/ApiHelpers.cs
@@ -17,8 +17,8 @@ public static partial class ApiHelpers
public static ApiClient? BuildApiClient(Type controller, List endpoints)
{
- var ignoreAttribute = controller.CustomAttributes.FirstOrDefault(x => x.AttributeType.FullName == typeof(TypeContractorIgnoreAttribute).FullName);
- if (ignoreAttribute is not null)
+ var hasIgnoreAttribute = controller.HasCustomAttribute(typeof(TypeContractorIgnoreAttribute).FullName ?? "");
+ if (hasIgnoreAttribute)
{
Log.Instance.LogDebug($"Controller {controller.Name} marked with Ignore. Skipping.");
return null;
@@ -50,6 +50,13 @@ public static partial class ApiHelpers
internal static List BuildApiEndpoint(MethodInfo endpoint)
{
+ // See if we should skip
+ if (endpoint.HasCustomAttribute(typeof(TypeContractorIgnoreAttribute).FullName ?? ""))
+ {
+ Log.Instance.LogDebug($"Method {endpoint.Name} marked with Ignore. Skipping.");
+ return [];
+ }
+
// Find HTTP method
var httpAttributes = endpoint
.CustomAttributes