2014-04-29 4 views
0

ICollection에서 엔티티와 관련 객체를 유지하려고합니다.Web Api OData 내비게이션 속성에 게시

System.Data.Services.Client.DataServiceRequestException : System.Data.Services.Client.DataServiceClientException : 없음 HTTP 리소스가 요청 URI 일치를 찾을 수 없습니다 '서비스 오류 메시지 (제거 서버 이름)입니다 .Facade.Reports/odata/Reports (8236)/LayoutData '를 선택하십시오.
템플릿 '~/entityset/key/navigation'을 사용하여 OData 경로에 대한 작업을 선택하는 라우팅 규칙이 없습니다.

일부 테스트 클라이언트 코드 :

string uriString = "Service.Facade.Reports/odata/"; 
Uri uri = new Uri(uriString); 
DataServiceContext context = new DataServiceContext(uri, DataServiceProtocolVersion.V3); 
var layoutData = new ReportLayoutData { Data = new byte[] { 1, 2, 3 } }; 
var list = new List<ReportLayoutData>(); 
list.Add(layoutData); 
var report = new ReportLayout { LayoutData = list, Name = "thing" }; 
context.AddObject("Reports", report); 
context.AddRelatedObject(report, "LayoutData", list[0]); //Newly Added for Web API 
DataServiceResponse response = context.SaveChanges(); 

호출없이 서비스를 AddRelatedObject하는 보고서를 추가로 사용할 수 있습니다. 그러나 탐색 속성은 서비스를 단계별로 실행할 때 자동으로 직렬화되지 않으므로 AddRelatedObject를 추가 한 것입니다. 이전에이 동일한 코드가 WCF Data Services에서 작동 (AddRelatedObject없이)되었으며 이제는 Web API로 변환하려고합니다. 내가이 무슨 생각 인 라우팅 규칙을 추가해야 할 것 같다 서비스 수준에서

:

public static void Register(HttpConfiguration config) 
{ 
    // Web API configuration and services 
    ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); 
    builder.EntitySet<ReportLayout>("Reports"); 
    builder.EntitySet<ReportLayoutData>("ReportLayoutData"); 
    builder.EntitySet<DatabaseInstance>("DataSources"); 
    builder.EntitySet<DataSourceObject>("DataSourceObject"); 
    config.Routes.MapODataRoute("odata", "odata", builder.GetEdmModel()); 

    // Web API routes 
    config.MapHttpAttributeRoutes(); 

    config.Routes.MapHttpRoute(
     name: "DefaultApi", 
     routeTemplate: "api/{controller}/{id}", 
     defaults: new { id = RouteParameter.Optional } 
    ); 
} 

내가 POST를 지원하기 위해 내 컨트롤러에이 추가 된/탐색 속성에 넣습니다.

// POST PUT odata/Reports(5)/LayoutData 
[AcceptVerbs("POST", "PUT")] 
public async Task<IHttpActionResult> CreateLink([FromODataUri] int key, string navigationProperty, [FromBody] Uri link) 
{ 
    if (!ModelState.IsValid) 
    { 
     return BadRequest(ModelState); 
    } 

    ReportLayout report = await db.Reports.FindAsync(key); 
    if (report == null) 
    { 
     return NotFound(); 
    } 

    switch (navigationProperty) 
    { 
     case "LayoutData": 
      string layoutKey = GetKeyFromLinkUri<string>(link); 
      ReportLayoutData reportLayout = await db.ReportsData.FindAsync(layoutKey); 
      if (reportLayout == null) 
      { 
       return NotFound(); 
      } 
      report.LayoutData = Enumerable.Range(0,0).Select(x=>reportLayout).ToList(); 
      await db.SaveChangesAsync(); 
      return StatusCode(HttpStatusCode.NoContent); 

     default: 
      return NotFound(); 
    } 
} 

// Helper method to extract the key from an OData link URI. 
private TKey GetKeyFromLinkUri<TKey>(Uri link) 
{ 
    TKey key = default(TKey); 

    // Get the route that was used for this request. 
    IHttpRoute route = Request.GetRouteData().Route; 

    // Create an equivalent self-hosted route. 
    IHttpRoute newRoute = new HttpRoute(route.RouteTemplate, 
     new HttpRouteValueDictionary(route.Defaults), 
     new HttpRouteValueDictionary(route.Constraints), 
     new HttpRouteValueDictionary(route.DataTokens), route.Handler); 

    // Create a fake GET request for the link URI. 
    var tmpRequest = new HttpRequestMessage(HttpMethod.Get, link); 

    // Send this request through the routing process. 
    var routeData = newRoute.GetRouteData(
     Request.GetConfiguration().VirtualPathRoot, tmpRequest); 

    // If the GET request matches the route, use the path segments to find the key. 
    if (routeData != null) 
    { 
     ODataPath path = tmpRequest.GetODataPath(); 
     var segment = path.Segments.OfType<KeyValuePathSegment>().FirstOrDefault(); 
     if (segment != null) 
     { 
      // Convert the segment into the key type. 
      key = (TKey)ODataUriUtils.ConvertFromUriLiteral(
       segment.Value, ODataVersion.V3); 
     } 
    } 
    return key; 
} 

는 포항 강판은

[Serializable] 
public partial class ReportLayout 
{ 
public const string DefaultName = "Report..."; 
public const string DefaultGroup = "Uncategorized"; 

public ReportLayout() 
{ 
    LayoutData = new List<ReportLayoutData>(); 
    Name = DefaultName; 
    Group = DefaultGroup; 
    UserDefinedQuery = false; 
} 

public virtual DatabaseInstance DatabaseInstance { get; set; } 
public virtual ICollection<ReportLayoutData> LayoutData { get; set; } 
public string Name { get; set; } 
public string Group { get; set; } 
public int ReportLayoutID { get; set; } 
public string Query { get; set; } 
public bool UserDefinedQuery { get; set; } 

public void SetData(byte[] data) 
{ 
    if (LayoutData.Count() > 0) 
    { 
     LayoutData.ElementAt(0).Data = data; 
    } 
    else 
    { 
     LayoutData.Add(new ReportLayoutData() {Data = data}); 
    } 
} 
} 

[Serializable] 
public class ReportLayoutData 
{ 
    public byte[] Data { get; set; } 
    public virtual ReportLayout ReportLayout { get; set; } 
    public int ReportLayoutDataID { get; set; } 
} 

답변

0

내가 거의 맞았지만 바보 같은 실수의 서버 측의 몇 너무 변경 될 필요가 클라이언트 측 코드를 만들었다 밝혀 사용. 에서 CreateLink 액션 내에서

서버 측 수정 :

  • report.LayoutData = Enumerable.Range(0,0).Select(x=>reportLayout).ToList(); => report.LayoutData = Enumerable.Range(0,1).Select(x=>reportLayout).ToList(); 이름 : Jeez의 바보 멍청!

    context.AddObject("Reports", report); 
    context.AddObject("ReportLayoutData", layoutData); 
    context.AddLink(report, "LayoutData", layoutData); 
    

    위 DataServicecontext 설치가 호출로 변환합니다 :

    // POST odata/Reports 
    public async Task<IHttpActionResult> Post(ReportLayout reportlayout) 
    
    // POST PUT odata/Reports(5)/LayoutData 
    [AcceptVerbs("POST", "PUT")] 
    public async Task<IHttpActionResult> CreateLink([FromODataUri] int key, string navigationProperty, [FromBody] Uri link) 
    

  • string layoutKey = GetKeyFromLinkUri<string>(link); => int layoutKey = GetKeyFromLinkUri<int>(link);

클라이언트 측 코드는 옳은 일을하기 위해 DataServiceContext를 슬쩍 찌르다 할뿐만 아니라 변경

관련 문제