datetime 매개 변수를 전달하는 방법은 무엇입니까?


92

웹 API에 UTC 날짜를 전달하는 방법은 무엇입니까?

전달 2010-01-01은 잘 작동하지만 2014-12-31T22:00:00.000Z(시간 구성 요소 포함)과 같은 UTC 날짜를 전달 하면 HTTP 404 응답을받습니다. 그래서

http://domain/api/controller/action/2012-12-31T22:00:00.000Z

404 오류 응답을 생성하는 반면

http://domain/api/controller/action/2012-12-31

잘 작동합니다.

UTC 날짜를 Web API에 전달하는 방법-또는 적어도 날짜 시간을 지정하는 방법은 무엇입니까?


2
날짜의 ":"가 용의자입니까? 탈출 해보세요. http://domain/api/controller/action/2012-12-31T22%3A00%3A00.000Z
shahkalpesh

2
탈출은 도움이되지 않습니다. 여전히 404.
Nickolodeon

전달 된 문자열에서 날짜로의 변환이 실패한 이유를 파악하기 위해 디버깅을 활성화 할 수 있습니까? 아이디어는 URL을 사용하여 전달한 날짜를 변환하는 데 사용되는 방법을 파악하는 것입니다.이 방법은 메서드 DateTime의 매개 변수 데이터 유형이라고 가정합니다.
shahkalpesh

4
내가 할게. 메소드에는 .NET DateTime 매개 변수가 필요합니다. 시간 구성 요소를 전달하지 못하고 그 방법에 대한 문서를 찾을 수 없다는 것이 어리석은 일이라고 생각합니다!
Nickolodeon 2013 년

2
완료되면 솔루션을 게시하십시오. 비슷한 문제를 가진 다른 사람들에게 도움이 될 수 있습니다. 감사.
shahkalpesh

답변:


34

문제는 두 가지입니다.

1. .경로에서

기본적으로 IIS는 점이있는 모든 URI를 정적 리소스로 취급하고이를 반환하고 추가 처리 (웹 API에 의한)를 모두 건너 뜁니다. 이것은 섹션의 Web.config에서 구성됩니다 . system.webServer.handlers기본 처리기가 처리합니다 path="*.". 이 path속성 에서 이상한 구문에 관한 문서를 많이 찾을 수는 없지만 (정규식이 더 의미가 있었을 것입니다), 이것이 분명히 의미하는 것은 "점을 포함하지 않는 모든 것"(그리고 아래 2 번 지점의 문자)입니다. 따라서 이름의 'Extensionless' ExtensionlessUrlHandler-Integrated-4.0.

제 생각에는 '정확성'의 순서로 여러 솔루션이 가능합니다.

  • 점을 허용해야하는 경로에 대해 특별히 새 핸들러를 추가하십시오. 기본값 앞에 추가 해야 합니다. 이렇게하려면 먼저 기본 처리기 를 제거 하고 나중에 다시 추가해야합니다.
  • path="*."속성을로 변경하십시오 path="*". 그런 다음 모든 것을 잡을 것입니다. 그때부터 웹 API는 더 이상 점이있는 수신 호출을 정적 리소스로 해석하지 않습니다. 웹 API에서 정적 리소스를 호스팅하는 경우 권장되지 않습니다!
  • Web.config에 다음을 추가하여 모든 요청을 무조건 처리합니다. under <system.webserver>:<modules runAllManagedModulesForAllRequests="true">

2. :경로에서

위의 내용을 변경하면 기본적으로 다음과 같은 오류가 발생합니다.

클라이언트 (:)에서 잠재적으로 위험한 Request.Path 값이 감지되었습니다.

Web.config에서 미리 정의 된 허용되지 않는 / 잘못된 문자를 변경할 수 있습니다. 아래 <system.web>에 다음을 추가합니다 <httpRuntime requestPathInvalidCharacters="&lt;,&gt;,%,&amp;,*,\,?" />.. :유효하지 않은 문자의 표준 목록에서를 제거했습니다 .

더 쉽고 안전한 솔루션

귀하의 질문에 대한 답변은 아니지만 더 안전하고 쉬운 해결책은이 모든 것이 필요하지 않도록 요청을 변경하는 것입니다. 이는 두 가지 방법으로 수행 할 수 있습니다.

  1. 날짜를와 같은 쿼리 문자열 매개 변수로 전달합니다 ?date=2012-12-31T22:00:00.000Z.
  2. 을 벗겨 .000모든 요청에서. 여전히 :'s (cfr point 2) 를 허용해야합니다 .

귀하의 "Easier Solution"은 기본적으로 몇 초가 필요하지 않았기 때문에 나를 위해 해주었습니다.
Neville

당신은 생명의 은인 :)입니다
Moeez

1
당신의 "쉬운 솔루션"에서, 대신 수의 :들, 당신이 바로 사용할 수 있다고 생각 %3A대신 :하고 그것을 잘해야합니다.
Mayer Spitzer 19 년

22

제품 웹 API 컨트롤러에서 :

[RoutePrefix("api/product")]
public class ProductController : ApiController
{
    private readonly IProductRepository _repository;
    public ProductController(IProductRepository repository)
    {
        this._repository = repository;
    }

    [HttpGet, Route("orders")]
    public async Task<IHttpActionResult> GetProductPeriodOrders(string productCode, DateTime dateStart, DateTime dateEnd)
    {
        try
        {
            IList<Order> orders = await _repository.GetPeriodOrdersAsync(productCode, dateStart.ToUniversalTime(), dateEnd.ToUniversalTime());
            return Ok(orders);
        }
        catch(Exception ex)
        {
            return NotFound();
        }
    }
}

Fiddler-Composer에서 GetProductPeriodOrders 메서드 테스트 :

http://localhost:46017/api/product/orders?productCode=100&dateStart=2016-12-01T00:00:00&dateEnd=2016-12-31T23:59:59

DateTime 형식 :

yyyy-MM-ddTHH:mm:ss

javascript pass parameter use moment.js

const dateStart = moment(startDate).format('YYYY-MM-DDTHH:mm:ss');
const dateEnd = moment(endDate).format('YYYY-MM-DDTHH:mm:ss');

18

나는 당신의 고통을 느낍니다 ... 또 다른 날짜 시간 형식 ... 당신이 필요로하는 것!

Web Api 2를 사용하면 경로 속성을 사용하여 매개 변수를 지정할 수 있습니다.

따라서 클래스 및 메서드의 속성을 사용하여 문제가있는이 utc 형식을 사용하여 REST URL을 코딩 할 수 있습니다 (분명히 ISO8601, 아마도 startDate.toISOString ()을 사용하여 도착했을 것입니다).

[Route(@"daterange/{startDate:regex(^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$)}/{endDate:regex(^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$)}")]
    [HttpGet]
    public IEnumerable<MyRecordType> GetByDateRange(DateTime startDate, DateTime endDate)

....하지만 이것은 하나의 날짜 (startDate)로 작동하지만 어떤 이유로 endDate가이 형식이면 작동하지 않습니다. 몇 시간 동안 디버깅되었지만 단서 만 예외는 콜론 ":"을 좋아하지 않는다고 말합니다. web.config가 다음으로 설정되어 있지만

<system.web>
    <compilation debug="true" targetFramework="4.5.1" />
    <httpRuntime targetFramework="4.5.1" requestPathInvalidCharacters="" />
</system.web>

따라서 다른 날짜 형식 (ISO 날짜 형식의 폴리 필에서 가져옴)을 만들고이를 Javascript 날짜에 추가합니다 (간결하게하기 위해 최대 분으로 만 변환).

if (!Date.prototype.toUTCDateTimeDigits) {
    (function () {

        function pad(number) {
            if (number < 10) {
                return '0' + number;
            }
            return number;
        }

        Date.prototype.toUTCDateTimeDigits = function () {
            return this.getUTCFullYear() +
              pad(this.getUTCMonth() + 1) +
              pad(this.getUTCDate()) +
              'T' +
              pad(this.getUTCHours()) +
              pad(this.getUTCMinutes()) +
              'Z';
        };

    }());
}

그런 다음 Web API 2 메서드에 날짜를 보낼 때 날짜를 문자열에서 날짜로 변환 할 수 있습니다.

[RoutePrefix("api/myrecordtype")]
public class MyRecordTypeController : ApiController
{


    [Route(@"daterange/{startDateString}/{endDateString}")]
    [HttpGet]
    public IEnumerable<MyRecordType> GetByDateRange([FromUri]string startDateString, [FromUri]string endDateString)
    {
        var startDate = BuildDateTimeFromYAFormat(startDateString);
        var endDate = BuildDateTimeFromYAFormat(endDateString);
    ...
    }

    /// <summary>
    /// Convert a UTC Date String of format yyyyMMddThhmmZ into a Local Date
    /// </summary>
    /// <param name="dateString"></param>
    /// <returns></returns>
    private DateTime BuildDateTimeFromYAFormat(string dateString)
    {
        Regex r = new Regex(@"^\d{4}\d{2}\d{2}T\d{2}\d{2}Z$");
        if (!r.IsMatch(dateString))
        {
            throw new FormatException(
                string.Format("{0} is not the correct format. Should be yyyyMMddThhmmZ", dateString)); 
        }

        DateTime dt = DateTime.ParseExact(dateString, "yyyyMMddThhmmZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);

        return dt;
    }

그래서 URL은

http://domain/api/myrecordtype/daterange/20140302T0003Z/20140302T1603Z

Hanselman은 여기에 몇 가지 관련 정보를 제공합니다.

http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx


WebAPI 메서드에서 datetime 매개 변수를 nullable DateTime (DateTime? startDateString, DateTime? endDateDtring)으로 가질 수 있습니다.
DotNet Fan

toISOString을 언급 해주셔서 감사합니다. 내 RESTful WCF 서비스는 URI의 두 날짜에서 잘 작동하므로 복잡한 날짜 변환이 필요하지 않았습니다. 구성 설정에도 불구하고 콜론을 좋아하지 않는 Web API의 특이한 점일 수 있습니다.
Neville

@Simon, endDate요청 URL에 후행 슬래시가 포함 된 경우 작동합니다. 안타깝게도이 정보를 어디서 발견했는지 기억할 수 없으며이 문제를 해결하는 방법도 모릅니다.
Pooven

이것을 사용하려는 24 시간 시계 사용자는 날짜 형식에서 hh를 HH로 변경해야합니다.
snaits

1
이것이 정답입니다. StackOverflow, 답을 내리지 마세요!
mghaoui

9

sk의 대답과 유사한 대안으로 Date.prototype.toISOString()쿼리 문자열에 형식이 지정된 날짜를 전달할 수 있습니다. 이것은 표준 ISO 8601 형식이며 라우트 또는 작업의 추가 구성없이 .Net Web API 컨트롤러에서 허용됩니다.

예 :

var dateString = dateObject.toISOString(); // "2019-07-01T04:00:00.000Z"

1
맞나요? 이것이 작동하는 예를 제공 할 수 있습니까? 동일한 해결 방법을 수행했지만 작동하지 않습니다.
anatol

@anatol 어떤 결과를 얻습니까? 제공된 코드는 dateObject초기화 된 Date객체 인 전제 조건이있는 작동 예제 입니다.
Bondolin

이것은 아마도 약간 투표되어야합니다. 이것은 UTC를 ISO로 변경하여 내 문제를 해결했습니다. 단일체
Regianni

1
다행 @Regianni 그것은 :-) 도움이
Bondolin

이것은 ISO 형식으로 날짜를 얻기 위해 stackoverflow.com/a/115034/1302730 을 사용하여 저에게
효과적이었습니다

7

이것은 가능한 솔루션의 솔루션이자 모델입니다. 클라이언트에서 Moment.js를 사용하여 날짜 형식을 지정하고 유닉스 시간으로 변환하십시오.

 $scope.startDate.unix()

경로 매개 변수를 길게 설정하십시오.

[Route("{startDate:long?}")]
public async Task<object[]> Get(long? startDate)
{
    DateTime? sDate = new DateTime();

        if (startDate != null)
        {
            sDate = new DateTime().FromUnixTime(startDate.Value); 
        }
        else
        {
            sDate = null;
        }
         ... your code here!
  }

Unix 시간에 대한 확장 메서드를 만듭니다. Unix DateTime 메서드


4

예전에는 힘든 작업 이었지만 이제는 toUTCString ()을 사용할 수 있습니다.

예:

[HttpPost]
public ActionResult Query(DateTime Start, DateTime End)

Ajax 게시물 요청에 아래를 입력하십시오.

data: {
    Start: new Date().toUTCString(),
    End: new Date().toUTCString()
},

3

사실, 매개 변수를 명시 적으로? date = 'fulldatetime'으로 지정하는 것은 매력처럼 작동했습니다. 따라서 이것은 현재 해결책이 될 것입니다. 쉼표를 사용하지 말고 오래된 GET 접근 방식을 사용하십시오.


0

ISO-8859-1 운영 체제를 인코딩했기 때문에 날짜 형식 "dd.MM.yyyy HH : mm : sss"는 InvariantCulture 문자열을 사용하는 것이 무엇인지 인식하지 못했습니다.

string url = "GetData?DagsPr=" + DagsProfs.ToString(CultureInfo.InvariantCulture)

0

코드를 살펴보면 DateTime 개체의 '시간'에 대해 걱정하지 않는다고 가정합니다. 그렇다면 날짜, 월 및 연도를 정수 매개 변수로 전달할 수 있습니다. 다음 코드를 참조하십시오. 이것은 내 현재 프로젝트의 실제 예제입니다.

장점은 다음과 같습니다. 이 방법은 DateTime 형식 문제와 문화적 비 호환성을 피하는 데 도움이됩니다.

    /// <summary>
    /// Get Arrivals Report Seven Day Forecast
    /// </summary>
    /// <param name="day"></param>
    /// <param name="month"></param>
    /// <param name="year"></param>
    /// <returns></returns>
    [HttpGet("arrivalreportsevendayforecast/{day:int}/{month:int}/{year:int}")]
    public async Task<ActionResult<List<ArrivalsReportSevenDayForecastModel>>> GetArrivalsReportSevenDayForecast(int day, int month, int year)
    {
        DateTime selectedDate = new DateTime(year, month, day);
        IList<ArrivalsReportSevenDayForecastModel> arrivingStudents = await _applicationService.Value.GetArrivalsReportSevenDayForecast(selectedDate);
        return Ok(arrivingStudents);
    }

프론트 엔드도보고 싶다면 아래 코드를 자유롭게 읽으십시오. 불행히도 Angular로 작성되었습니다. 이것이 Angular GET 요청에서 일반적으로 DateTime을 쿼리 매개 변수로 전달하는 방법입니다.

public getArrivalsReportSevenDayForecast(selectedDate1 : Date): Observable<ArrivalsReportSevenDayForecastModel[]> {
const params = new HttpParams();
const day = selectedDate1.getDate();
const month = selectedDate1.getMonth() + 1
const year = selectedDate1.getFullYear();

const data = this.svcHttp.get<ArrivalsReportSevenDayForecastModel[]>(this.routePrefix +
  `/arrivalreportsevendayforecast/${day}/${month}/${year}`, { params: params }).pipe(
  map<ArrivalsReportSevenDayForecastModel[], ArrivalsReportSevenDayForecastModel[]>(arrivingList => {
    // do mapping here if needed       
    return arrivingList;
  }),
  catchError((err) => this.svcError.handleError(err)));

return data;
}

0

가능한 해결책 중 하나는 Ticks를 사용하는 것입니다.

public long Ticks {get; }

그런 다음 컨트롤러의 방법에서 :

공개 DateTime (긴 틱);

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.