@@ -32,6 +32,7 @@ public abstract class ControllerBase
32
32
private IModelBinderFactory _modelBinderFactory ;
33
33
private IObjectModelValidator _objectValidator ;
34
34
private IUrlHelper _url ;
35
+ private ProblemDetailsFactory _problemDetailsFactory ;
35
36
36
37
/// <summary>
37
38
/// Gets the <see cref="Http.HttpContext"/> for the executing action.
@@ -190,6 +191,28 @@ public IObjectModelValidator ObjectValidator
190
191
}
191
192
}
192
193
194
+ public ProblemDetailsFactory ProblemDetailsFactory
195
+ {
196
+ get
197
+ {
198
+ if ( _problemDetailsFactory == null )
199
+ {
200
+ _problemDetailsFactory = HttpContext ? . RequestServices ? . GetRequiredService < ProblemDetailsFactory > ( ) ;
201
+ }
202
+
203
+ return _problemDetailsFactory ;
204
+ }
205
+ set
206
+ {
207
+ if ( value == null )
208
+ {
209
+ throw new ArgumentNullException ( nameof ( value ) ) ;
210
+ }
211
+
212
+ _problemDetailsFactory = value ;
213
+ }
214
+ }
215
+
193
216
/// <summary>
194
217
/// Gets the <see cref="ClaimsPrincipal"/> for user associated with the executing action.
195
218
/// </summary>
@@ -1823,51 +1846,33 @@ public virtual ConflictObjectResult Conflict([ActionResultObjectValue] ModelStat
1823
1846
=> new ConflictObjectResult ( modelState ) ;
1824
1847
1825
1848
/// <summary>
1826
- /// Creates an <see cref="ObjectResult"/> that produces a <see cref="ProblemDetails"/> response with a <c>500</c>
1827
- /// error status with a <see cref="ProblemDetails" /> value.
1849
+ /// Creates an <see cref="ObjectResult"/> that produces a <see cref="ProblemDetails"/> response.
1828
1850
/// </summary>
1829
- /// <param name="title">The value for <see cref="ProblemDetails.Title" />.</param>
1830
- /// <param name="type">The value for <see cref="ProblemDetails.Type" />.</param>
1851
+ /// <param name="statusCode">The value for <see cref="ProblemDetails.Status" />..</param>
1831
1852
/// <param name="detail">The value for <see cref="ProblemDetails.Detail" />.</param>
1832
1853
/// <param name="instance">The value for <see cref="ProblemDetails.Instance" />.</param>
1854
+ /// <param name="title">The value for <see cref="ProblemDetails.Title" />.</param>
1855
+ /// <param name="type">The value for <see cref="ProblemDetails.Type" />.</param>
1833
1856
/// <returns>The created <see cref="ObjectResult"/> for the response.</returns>
1834
1857
[ NonAction ]
1835
1858
public virtual ObjectResult Problem (
1836
1859
string detail = null ,
1837
1860
string instance = null ,
1861
+ int ? statusCode = null ,
1838
1862
string title = null ,
1839
1863
string type = null )
1840
1864
{
1841
- var problemDetails = new ProblemDetails
1842
- {
1843
- Title = title ,
1844
- Type = type ,
1845
- Detail = detail ,
1846
- Instance = instance ,
1847
- } ;
1848
-
1849
- ApplyProblemDetailsDefaults ( problemDetails , statusCode : 500 ) ;
1865
+ var problemDetails = ProblemDetailsFactory . CreateProblemDetails (
1866
+ HttpContext ,
1867
+ statusCode : statusCode ?? 500 ,
1868
+ title : title ,
1869
+ type : type ,
1870
+ detail : detail ,
1871
+ instance : instance ) ;
1850
1872
1851
1873
return new ObjectResult ( problemDetails ) ;
1852
1874
}
1853
1875
1854
- private void ApplyProblemDetailsDefaults ( ProblemDetails problemDetails , int statusCode )
1855
- {
1856
- problemDetails . Status = statusCode ;
1857
-
1858
- if ( problemDetails . Title is null || problemDetails . Type is null )
1859
- {
1860
- var options = HttpContext . RequestServices . GetRequiredService < IOptions < ApiBehaviorOptions > > ( ) . Value ;
1861
- if ( options . ClientErrorMapping . TryGetValue ( statusCode , out var clientErrorData ) )
1862
- {
1863
- problemDetails . Title ??= clientErrorData . Title ;
1864
- problemDetails . Type ??= clientErrorData . Link ;
1865
- }
1866
- }
1867
-
1868
- ProblemDetailsClientErrorFactory . SetTraceId ( ControllerContext , problemDetails ) ;
1869
- }
1870
-
1871
1876
/// <summary>
1872
1877
/// Creates an <see cref="BadRequestObjectResult"/> that produces a <see cref="StatusCodes.Status400BadRequest"/> response.
1873
1878
/// </summary>
@@ -1884,70 +1889,64 @@ public virtual ActionResult ValidationProblem([ActionResultObjectValue] Validati
1884
1889
}
1885
1890
1886
1891
/// <summary>
1887
- /// Creates an <see cref="BadRequestObjectResult "/> that produces a <see cref="StatusCodes.Status400BadRequest"/> response
1892
+ /// Creates an <see cref="ActionResult "/> that produces a <see cref="StatusCodes.Status400BadRequest"/> response
1888
1893
/// with validation errors from <paramref name="modelStateDictionary"/>.
1889
1894
/// </summary>
1890
1895
/// <param name="modelStateDictionary">The <see cref="ModelStateDictionary"/>.</param>
1891
1896
/// <returns>The created <see cref="BadRequestObjectResult"/> for the response.</returns>
1892
1897
[ NonAction ]
1893
1898
public virtual ActionResult ValidationProblem ( [ ActionResultObjectValue ] ModelStateDictionary modelStateDictionary )
1894
- {
1895
- if ( modelStateDictionary == null )
1896
- {
1897
- throw new ArgumentNullException ( nameof ( modelStateDictionary ) ) ;
1898
- }
1899
+ => ValidationProblem ( detail : null , modelStateDictionary : modelStateDictionary ) ;
1899
1900
1900
- var validationProblem = new ValidationProblemDetails ( modelStateDictionary ) ;
1901
- ApplyProblemDetailsDefaults ( validationProblem , statusCode : 400 ) ;
1902
-
1903
- return new BadRequestObjectResult ( validationProblem ) ;
1904
- }
1905
1901
1906
1902
/// <summary>
1907
- /// Creates an <see cref="BadRequestObjectResult "/> that produces a <see cref="StatusCodes.Status400BadRequest"/> response
1903
+ /// Creates an <see cref="ActionResult "/> that produces a <see cref="StatusCodes.Status400BadRequest"/> response
1908
1904
/// with validation errors from <see cref="ModelState"/>.
1909
1905
/// </summary>
1910
- /// <returns>The created <see cref="BadRequestObjectResult "/> for the response.</returns>
1906
+ /// <returns>The created <see cref="ActionResult "/> for the response.</returns>
1911
1907
[ NonAction ]
1912
- public virtual ActionResult ValidationProblem ( ) => ValidationProblem ( ModelState ) ;
1908
+ public virtual ActionResult ValidationProblem ( )
1909
+ => ValidationProblem ( ModelState ) ;
1913
1910
1914
1911
/// <summary>
1915
- /// Creates an <see cref="BadRequestObjectResult "/> that produces a <see cref="StatusCodes.Status400BadRequest"/> response
1912
+ /// Creates an <see cref="ActionResult "/> that produces a <see cref="StatusCodes.Status400BadRequest"/> response
1916
1913
/// with a <see cref="ValidationProblemDetails"/> value.
1917
1914
/// </summary>
1918
- /// <param name="title">The value for <see cref="ProblemDetails.Title" />.</param>
1919
- /// <param name="type">The value for <see cref="ProblemDetails.Type" />.</param>
1920
1915
/// <param name="detail">The value for <see cref="ProblemDetails.Detail" />.</param>
1921
1916
/// <param name="instance">The value for <see cref="ProblemDetails.Instance" />.</param>
1917
+ /// <param name="statusCode">The status code.</param>
1918
+ /// <param name="title">The value for <see cref="ProblemDetails.Title" />.</param>
1919
+ /// <param name="type">The value for <see cref="ProblemDetails.Type" />.</param>
1922
1920
/// <param name="modelStateDictionary">The <see cref="ModelStateDictionary"/>.
1923
1921
/// When <see langword="null"/> uses <see cref="ModelState"/>.</param>
1924
- /// <returns>The created <see cref="BadRequestObjectResult "/> for the response.</returns>
1922
+ /// <returns>The created <see cref="ActionResult "/> for the response.</returns>
1925
1923
[ NonAction ]
1926
1924
public virtual ActionResult ValidationProblem (
1927
- string detail ,
1925
+ string detail = null ,
1928
1926
string instance = null ,
1927
+ int ? statusCode = null ,
1929
1928
string title = null ,
1930
1929
string type = null ,
1931
1930
[ ActionResultObjectValue ] ModelStateDictionary modelStateDictionary = null )
1932
1931
{
1933
1932
modelStateDictionary ??= ModelState ;
1934
1933
1935
- var validationProblem = new ValidationProblemDetails ( modelStateDictionary )
1936
- {
1937
- Detail = detail ,
1938
- Instance = instance ,
1939
- Type = type ,
1940
- } ;
1934
+ var validationProblem = ProblemDetailsFactory . CreateValidationProblemDetails (
1935
+ HttpContext ,
1936
+ modelStateDictionary ,
1937
+ statusCode : statusCode ,
1938
+ title : title ,
1939
+ type : type ,
1940
+ detail : detail ,
1941
+ instance : instance ) ;
1941
1942
1942
- if ( title != null )
1943
+ if ( validationProblem . Status == 400 )
1943
1944
{
1944
- // ValidationProblemDetails has a Title by default. Do not overwrite it with a null
1945
- validationProblem . Title = title ;
1945
+ // For compatibility with 2.x, continue producing BadRequestObjectResult instances if the status code is 400.
1946
+ return new BadRequestObjectResult ( validationProblem ) ;
1946
1947
}
1947
1948
1948
- ApplyProblemDetailsDefaults ( validationProblem , statusCode : 400 ) ;
1949
-
1950
- return new BadRequestObjectResult ( validationProblem ) ;
1949
+ return new ObjectResult ( validationProblem ) ;
1951
1950
}
1952
1951
1953
1952
/// <summary>
0 commit comments