2

我很确定它没有,但如果这个问题已经被问过,我很抱歉。如果这只是一个愚蠢的问题,另外道歉,但我觉得我要么完全错过了一些东西,要么有正确的想法,只需要一些备份来保持我自己的理智。

我一直在我们的应用程序中实现 WCF 数据服务 5.0,并且读取操作返回实体对象没有问题。

不幸的是,在服务操作方面存在令人讨厌的限制,即它们只能返回原始类型(请参阅 MSDN)。考虑到实体对象没有问题,这很烦人。

我知道一种解决方法是创建一个“虚拟”复杂类型,因为 WCFDS 会识别这一点,但我不想只是将随机 POCO 扔到我的数据模型中,而这些数据模型实际上并不在数据库中。

所以我想到的解决方案是为我的对象创建一个扩展方法,该方法可以将它们序列化为 JSON 字符串以由服务返回。我的问题是;是否有任何令人信服的论点为什么我不应该这样做,或者任何人都可以提出更好的选择?


编辑:澄清我当前问题的附加信息

我创建了一个非常简单的示例,说明我正在做的事情最初提出了这个问题。我的服务类首先如下:

[JsonpSupportBehavior]
public partial class SchedulingService : DataService<ChronosDataContext>, ISchedulingService
{
    public static void InitializeService(DataServiceConfiguration config)
    {
        #if DEBUG
        config.UseVerboseErrors = true;
        #endif

        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;

        config.SetServiceOperationAccessRule(
        "TestService",
        ServiceOperationRights.All);
    }

    [WebGet]
    public SchedulingResult TestService(
         string testParam1,
         string testParam2)
    {
         // NOTE: I never use the params, they're just there for this example.
         SchedulingResult result = SchedulingResult.Empty;

         result.Status = OperationStatus.Success;
         result.ResponseID = Guid.NewGuid();
         result.AffectedIDs = new List<int>(new int[] { 1, 2, 3, 4, 5, 6, 7 });
         result.RecordsAffected = 10;

         return result;
    }
}

尝试使用我的浏览器访问此服务,我收到以下请求错误:

The server encountered an error processing the request. The exception message is 
'Unable to load metadata for return type 
    'Chronos.Services.SchedulingResult' of method 
    'Chronos.Services.SchedulingResult TestService(System.String, System.String)'.'. 
See server logs for more details. 

The exception stack trace is:
at System.Data.Services.Providers.BaseServiceProvider.AddServiceOperation(MethodInfo method, String protocolMethod) 
at System.Data.Services.Providers.BaseServiceProvider.AddOperationsFromType(Type type) 
at System.Data.Services.Providers.BaseServiceProvider.LoadMetadata() 
at System.Data.Services.DataService`1.CreateMetadataAndQueryProviders(IDataServiceMetadataProvider& metadataProviderInstance, IDataServiceQueryProvider& queryProviderInstance, BaseServiceProvider& builtInProvider, Object& dataSourceInstance) 
at System.Data.Services.DataService`1.CreateProvider() 
at System.Data.Services.DataService`1.HandleRequest() 
at System.Data.Services.DataService`1.ProcessRequestForMessage(Stream messageBody) 
at SyncInvokeProcessRequestForMessage(Object , Object[] , Object[] ) 
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs) 
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc) 
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc) 
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc& rpc) 
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc) 
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc) 
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& rpc) 
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc) 
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc) 
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc) 
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

以下是构成我试图返回的 SchedulingResult 的类:

public class SchedulingResult : ServiceInvocationResponse
{
    public SchedulingResult()
        : base()
    {
        this.Payload = new object[] 
        {
            new List<int>(),
            new List<int>()
        };
    }

    public List<int> AffectedIDs 
    {
        get { return (List<int>)Payload[0]; }
        set { Payload[0] = value; }
    }

    public List<int> FailedIDs
    {
        get { return (List<int>)Payload[1]; }
        set { Payload[1] = value; }
    }

    public static SchedulingResult Empty
    {
        get { return new SchedulingResult(); }
    }
}

public class ServiceInvocationResponse : AbstractJsonObject<ServiceInvocationResponse>
{
    public ServiceInvocationResponse()
    {
        this.Status = OperationStatus.Unknown;
        this.Severity = ErrorSeverity.None;
    }

    public virtual int RecordsAffected { get; set; }

    public virtual Exception ErrorObject { get; set; }

    internal virtual object[] Payload { get; set; }
}


public abstract class AbstractJsonObject<TBaseType>
{
    public virtual object Deserialize(string source)
    {
        return JsonConvert.DeserializeObject(source);
    }

    public virtual T Deserialize<T>(string source)
    {
        return JsonConvert.DeserializeObject<T>(source);
    }

    public string Serialize()
    {
        return JsonConvert.SerializeObject(
            this, Formatting.Indented);
    }

    public override string ToString()
    {
        return this.Serialize();
    }

    public static TBaseType FromString(string json)
    {
        return JsonConvert.DeserializeObject<TBaseType>(json);
    }
}
4

1 回答 1

3

可以从服务操作返回一种或多种原始、复杂或实体类型。

  • 原始类型是您所期望的:string、int、bool 等。
  • 复杂类型是没有唯一键的类(命名ID的属性或[DataServiceKey("<yourkeyhere>")]属性)
  • 实体类型是具有唯一键的类

例如:

using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Web;

namespace Scratch.Web
{
    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    public class ScratchService : DataService<ScratchContext>
    {
        public static void InitializeService(DataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule("*", EntitySetRights.All);
            config.SetServiceOperationAccessRule("*", ServiceOperationRights.AllRead);
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
            config.UseVerboseErrors = true;
        }

        [WebGet]
        public string GetPrimitive()
        {
            return "Success";
        }

        [WebGet]
        public IQueryable<string> GetPrimitives()
        {
            return new[] { "Success", "Hello World" }.AsQueryable();
        }

        [WebGet]
        public ComplexType GetComplexType()
        {
            return new ComplexType { Property1 = "Success", Property2 = "Hello World" };
        }

        [WebGet]
        public IQueryable<ComplexType> GetComplexTypes()
        {
            return new[] {
                           new ComplexType { Property1 = "Success", Property2 = "Hello World" },
                           new ComplexType { Property1 = "Success", Property2 = "Hello World" }
                       }.AsQueryable();
        }

        [WebGet]
        public EntityType GetEntityType()
        {
            return new EntityType { Property1 = "Success", Property2 = "Hello World" };
        }

        [WebGet]
        public IQueryable<EntityType> GetEntityTypes()
        {
            return new[] {
                           new EntityType { Property1 = "Success1", Property2 = "Hello World" },
                           new EntityType { Property1 = "Success2", Property2 = "Hello World" }
                       }.AsQueryable();
        }
    }

    public class ScratchContext { }

    public class ComplexType
    {
        public string Property1 { get; set; }
        public string Property2 { get; set; }
    }

    [DataServiceKey("Property1")]
    public class EntityType
    {
        public string Property1 { get; set; }
        public string Property2 { get; set; }
    }
}

也许您遇到了其他问题?

于 2012-07-12T17:56:03.550 回答