public object GetChanges()
        {
            var changes = _values
                          .Select(pair =>
            {
                var value = pair.Value;
                object snapshot;
                if (_snapshot.TryGetValue(pair.Key, out snapshot) && Equals(value, snapshot))
                {
                    var tracking = value as IChangeTracking;
                    if (tracking == null)
                    {
                        return(null);
                    }
                    value = tracking.GetChanges();
                    if (value == null)
                    {
                        return(null);
                    }
                }
                return(new { pair.Key, value });
            })
                          .Where(item => item != null)
                          .ToDictionary(item => item.Key, item => item.value);

            if (changes.Count == 0)
            {
                return(null);
            }
            var resource = new SDataResource(changes);

            ((ISDataProtocolObject)resource).Info = _info;
            return(resource);
        }
        private SDataRequest CreateBatchRequest(ICollection <SDataParameters> items)
        {
            Guard.ArgumentNotNull(items, "items");

            var       resources     = new SDataCollection <SDataResource>(items.Count);
            string    path          = null;
            MediaType?contentType   = null;
            var       include       = new List <string>();
            var       select        = new List <string>();
            int?      precedence    = null;
            MediaType?format        = null;
            string    language      = null;
            string    version       = null;
            var       accept        = new List <MediaType>();
            var       form          = new Dictionary <string, string>();
            var       files         = new List <AttachedFile>();
            var       extensionArgs = new Dictionary <string, string>();

            foreach (var parms in items)
            {
                if (parms.StartIndex != null)
                {
                    throw new NotSupportedException("StartIndex not supported in batch requests");
                }
                if (parms.Count != null)
                {
                    throw new NotSupportedException("Count not supported in batch requests");
                }
                if (parms.Where != null)
                {
                    throw new NotSupportedException("Where not supported in batch requests");
                }
                if (parms.OrderBy != null)
                {
                    throw new NotSupportedException("OrderBy not supported in batch requests");
                }
                if (parms.Search != null)
                {
                    throw new NotSupportedException("Search not supported in batch requests");
                }
                if (parms.TrackingId != null)
                {
                    throw new NotSupportedException("TrackingId not supported in batch requests");
                }
                if (parms.IncludeSchema != null)
                {
                    throw new NotSupportedException("IncludeSchema not supported in batch requests");
                }
                if (parms.ReturnDelta != null)
                {
                    throw new NotSupportedException("ReturnDelta not supported in batch requests");
                }
                if (parms.Path != path)
                {
                    if (path != null)
                    {
                        throw new SDataClientException("All non-null path values must be the same");
                    }
                    path = parms.Path;
                }
                if (parms.ContentType != contentType)
                {
                    if (contentType != null)
                    {
                        throw new SDataClientException("All non-null content type values must be the same");
                    }
                    contentType = parms.ContentType;
                }
                if (parms.Include != null)
                {
                    include.AddRange(parms.Include.Split(','));
                }
                if (parms.Select != null)
                {
                    select.AddRange(parms.Select.Split(','));
                }
                if (parms.Precedence != null && parms.Precedence != precedence)
                {
                    precedence = Math.Max(precedence ?? 0, parms.Precedence.Value);
                }
                if (parms.Format != format)
                {
                    if (format != null)
                    {
                        throw new SDataClientException("All non-null format values must be the same");
                    }
                    format = parms.Format;
                }
                if (parms.Language != language)
                {
                    if (language != null)
                    {
                        throw new SDataClientException("All non-null language values must be the same");
                    }
                    language = parms.Language;
                }
                if (parms.Version != version)
                {
                    if (version != null)
                    {
                        throw new SDataClientException("All non-null version values must be the same");
                    }
                    version = parms.Version;
                }
                if (parms.Accept != null)
                {
                    accept.AddRange(parms.Accept);
                }
                foreach (var data in parms.Form)
                {
                    form.Add(data.Key, data.Value);
                }
                files.AddRange(parms.Files);
                foreach (var arg in parms.ExtensionArgs)
                {
                    extensionArgs[arg.Key] = arg.Value;
                }

                SDataResource resource;
                if (parms.Content == null)
                {
                    resource = new SDataResource();
                }
                else
                {
                    var content = parms.Content;
                    if (parms.Method == HttpMethod.Put && DifferentialUpdate)
                    {
                        var tracking = content as IChangeTracking;
                        if (tracking != null)
                        {
                            content = tracking.GetChanges();
                            if (content == null)
                            {
                                throw new SDataClientException("Content doesn't have any changes");
                            }
                        }
                    }

                    resource = ContentHelper.Serialize(content, NamingScheme) as SDataResource;
                    if (resource == null)
                    {
                        throw new SDataClientException("Only resources can be submitted in batch requests");
                    }
                }

                resource.HttpMethod = parms.Method;
                if (parms.Method != HttpMethod.Post)
                {
                    if (resource.Key == null)
                    {
                        throw new SDataClientException("A selector must be specified for GET, PUT and DELETE batch requests");
                    }

                    var itemUri = new SDataUri(Uri)
                    {
                        Include    = parms.Include,
                        Select     = parms.Select,
                        Precedence = parms.Precedence
                    };
                    if (path != null)
                    {
                        itemUri.AppendPath(path);
                    }
                    itemUri.LastPathSegment.Selector = SDataUri.FormatConstant(resource.Key);
                    resource.Id  = itemUri.AbsoluteUri;
                    resource.Url = itemUri.Uri;
                }

                if (parms.ETag != null)
                {
                    resource.IfMatch = parms.ETag;
                }

                resources.Add(resource);
            }

            var uri = new SDataUri(Uri)
            {
                Precedence = precedence,
                Format     = format ?? Format,
                Language   = language ?? Language,
                Version    = version ?? Version
            };

            if (path != null)
            {
                uri.AppendPath(path);
            }
            uri.AppendPath("$batch");
            if (include.Count > 0)
            {
                uri.Include = string.Join(",", include.Distinct().ToArray());
            }
            if (select.Count > 0)
            {
                uri.Select = string.Join(",", select.Distinct().ToArray());
            }
            foreach (var arg in extensionArgs)
            {
                uri["_" + arg.Key] = arg.Value;
            }

            var request = CreateRequest(uri, HttpMethod.Post, resources);

            request.ContentType = contentType ?? Format;

            if (accept.Count > 0)
            {
                request.Accept = accept.Distinct().ToArray();
            }
            foreach (var data in form)
            {
                request.Form.Add(data.Key, data.Value);
            }
            foreach (var file in files)
            {
                request.Files.Add(file);
            }
            if (language != null)
            {
                request.AcceptLanguage = language ?? Language;
            }

            TraceRequest(request);
            return(request);
        }
Beispiel #3
0
        private static T GetServiceResult <T>(ISDataClient client, Expression bodyExpr, SDataResource content)
        {
            var value    = content["response"];
            var response = (SDataResource)value;

            var attr = ((MethodCallExpression)bodyExpr).Method.GetCustomAttribute <SDataServiceOperationAttribute>();

            if (attr != null && !string.IsNullOrEmpty(attr.ResultPropertyName))
            {
                value = response[attr.ResultPropertyName];
            }
            else if (response.Count == 1)
            {
                var firstValue = response.Values.First();
                var type       = typeof(T);
                type = Nullable.GetUnderlyingType(type) ?? type;
                if (ContentHelper.IsObject(type) == ContentHelper.IsObject(firstValue))
                {
                    value = firstValue;
                }
            }

            var result   = ContentHelper.Deserialize <T>(value, client.NamingScheme);
            var tracking = result as IChangeTracking;

            if (tracking != null)
            {
                tracking.AcceptChanges();
            }
            return(result);
        }
Beispiel #4
0
        private static SDataParameters GetServiceParameters(ISDataClient client, Expression bodyExpr, string path)
        {
            Guard.ArgumentNotNull(client, "client");

            var callExpr = bodyExpr as MethodCallExpression;

            if (callExpr == null)
            {
                throw new SDataClientException("Expression must be a method call");
            }

            var attr         = callExpr.Method.GetCustomAttribute <SDataServiceOperationAttribute>();
            var namingScheme = client.NamingScheme ?? NamingScheme.Default;
            var request      = new SDataResource();
            var instance     = callExpr.Object != null?Expression.Lambda(callExpr.Object).Compile().DynamicInvoke() : null;

            if (path == null)
            {
                path = SDataPathAttribute.GetPath(instance != null ? instance.GetType() : callExpr.Method.DeclaringType);
            }

            if (instance != null)
            {
                if (attr == null || attr.PassInstanceBy == InstancePassingConvention.Selector ||
                    (attr.PassInstanceBy == InstancePassingConvention.Default && string.IsNullOrEmpty(attr.InstancePropertyName)))
                {
                    if (path == null)
                    {
                        throw new SDataClientException("Path must be specified when passing instance context by selector");
                    }
                    var key = ContentHelper.GetProtocolValue <string>(instance, SDataProtocolProperty.Key);
                    if (string.IsNullOrEmpty(key))
                    {
                        throw new SDataClientException("Unable to extract resource key from instance");
                    }
                    path += string.Format("({0})", SDataUri.FormatConstant(key));
                }
                else if (attr.PassInstanceBy == InstancePassingConvention.Default)
                {
                    var key = ContentHelper.GetProtocolValue <string>(instance, SDataProtocolProperty.Key);
                    request[attr.InstancePropertyName] = !string.IsNullOrEmpty(key) ? key : instance;
                }
                else
                {
                    if (string.IsNullOrEmpty(attr.InstancePropertyName))
                    {
                        throw new SDataClientException("Instance property name must be specified when passing instance context by key property or object property");
                    }

                    if (attr.PassInstanceBy == InstancePassingConvention.KeyProperty)
                    {
                        var key = ContentHelper.GetProtocolValue <string>(instance, SDataProtocolProperty.Key);
                        if (string.IsNullOrEmpty(key))
                        {
                            throw new SDataClientException("Unable to extract resource key from instance");
                        }
                        request[attr.InstancePropertyName] = key;
                    }
                    else if (attr.PassInstanceBy == InstancePassingConvention.ObjectProperty)
                    {
                        request[attr.InstancePropertyName] = instance;
                    }
                }
            }

            if (path != null)
            {
                path += "/";
            }
            path += "$service/" + namingScheme.GetName(callExpr.Method);

            foreach (var pair in callExpr.Method.GetParameters().Zip(callExpr.Arguments, (param, arg) => new { param, arg }))
            {
                request[namingScheme.GetName(pair.param)] = Expression.Lambda(pair.arg).Compile().DynamicInvoke();
            }

            var xmlLocalName = attr != null ? attr.XmlLocalName : null;
            var xmlNamespace = attr != null ? attr.XmlNamespace : null;
            var content      = new SDataResource(xmlLocalName, xmlNamespace)
            {
                { "request", request }
            };

            return(new SDataParameters
            {
                Method = HttpMethod.Post,
                Path = path,
                Content = content
            });
        }
 public ResourceCustomTypeDescriptor(SDataResource instance)
 {
     _instance = instance;
 }