Ejemplo n.º 1
0
        public static DbSyncScopeDescription GetDescriptionFromUri(ArgsParser parser, string uriString,
                                                                   out string serviceUri)
        {
            // Issue the request.
            var request = new WebClient();

            SyncSvcUtil.Log("Trying to connect to Uri '{0}' to check for SyncScopeSchema document", uriString);

            var content = request.DownloadString(uriString);

            // Check to see if its a SyncScopes <services> document or an SyncScopeSchema <edmx> document.
            if (parser.UseVerbose)
            {
                SyncSvcUtil.Log(
                    "Download succeeded. Checking to see if its a SyncScope <Service> document or an SyncScopeSchema <edmx> document.");
                SyncSvcUtil.Log("Downloaded document content:\n {0}", content);
            }

            SyncSvcUtil.Log("Parsing downloaded document.", uriString);

            var document = XDocument.Parse(content);

            if (document == null)
            {
                throw new CsdlException("Downloaded content is not a valid XML document.");
            }

            if (document.Root.Name.Equals(Constants.SyncScopeServicesElement))
            {
                if (parser.UseVerbose)
                {
                    SyncSvcUtil.Log("Found a <service> document. Checking for SyncScopes workspace.");
                }
                var workspaceElement = document.Root.Element(Constants.SyncScopeWorkspaceElement);
                if (workspaceElement == null)
                {
                    throw new CsdlException("Remote SyncScope services document did not contain a <workspace> element.");
                }

                // Look for <collection> element
                var collectionElements =
                    workspaceElement.Elements(Constants.SyncScopeWorkspaceCollectionElement).ToArray();
                if (collectionElements.Length == 0)
                {
                    throw new CsdlException("Remote SyncScope services document did not contain a <collection> element.");
                }
                XAttribute hrefAttr;
                if (collectionElements.Length > 1)
                {
                    SyncSvcUtil.Log(
                        "Multiple SyncScopes were found in the <service> document. Please specify the correct Url.");
                    foreach (var elem in collectionElements)
                    {
                        hrefAttr = elem.Attribute(Constants.SyncScopeWorkspaceCollectionHrefAttribute);
                        SyncSvcUtil.Log("\t\t{0} - Uri: {1}{2}{0}/$metadata",
                                        hrefAttr.Value,
                                        parser.CSDLUrl,
                                        parser.CSDLUrl.EndsWith("/") ? string.Empty : "/");
                    }
                    throw new CsdlException("Multiple SyncScopes found.");
                }
                // We have exactly one SyncScope. Download the schema for that
                hrefAttr = collectionElements[0].Attribute(Constants.SyncScopeWorkspaceCollectionHrefAttribute);
                if (hrefAttr == null)
                {
                    throw new CsdlException("No Href attribute was found in the <collection> element.");
                }

                // Ensure the href param is not empty as this is the scopeName
                if (string.IsNullOrEmpty(hrefAttr.Value))
                {
                    throw new CsdlException(
                              string.Format("Href attribute in <collection> must have a non empty string.\n Content: {0}",
                                            collectionElements[0]));
                }

                // Look for and remove $syncScopes
                var origUrl = parser.CSDLUrl;
                if (origUrl.EndsWith("$syncscopes", StringComparison.InvariantCultureIgnoreCase))
                {
                    origUrl = origUrl.Substring(0, origUrl.LastIndexOf("/"));
                }

                uriString = string.Format("{0}{1}{2}/$metadata",
                                          origUrl,
                                          origUrl.EndsWith("/") ? string.Empty : "/",
                                          hrefAttr.Value);

                return(GetDescriptionFromUri(parser, uriString, out serviceUri));
            }
            if (document.Root.Name.Equals(Constants.SyncScopeEdmxElement))
            {
                // Set the service URI and remove $metadata token from it.
                //Remove the / at the end if present.
                serviceUri = (uriString.EndsWith("/")) ? uriString.Substring(0, uriString.Length - 1) : uriString;

                //The service will render the schema only if there is a $metadata at the end in the Uri.
                serviceUri = serviceUri.Substring(0, serviceUri.Length - "/$metadata".Length);

                //Remove the scope name
                serviceUri = serviceUri.Substring(0, serviceUri.LastIndexOf("/") + 1);

                return(ParseCSDLDocument(parser, uriString, document));
            }
            throw new CsdlException(
                      string.Format("Downloaded XML content is not a valid <service> document. \nDocument Content: {0}",
                                    content));
        }
Ejemplo n.º 2
0
        private static DbSyncScopeDescription ParseCSDLDocument(ArgsParser parser, string uriString, XDocument document)
        {
            DbSyncScopeDescription scopeDescription = null;
            var uri = new Uri(uriString);
            // Assumption is that for OData Sync metadata document, the URI is of format http://foo/snc.svc/scopename/$metadata.
            // In this case we are looking for the last but one segment.
            var scopeName = uri.Segments[uri.Segments.Length - 2];

            if (scopeName.EndsWith("/"))
            {
                scopeName = scopeName.Substring(0, scopeName.Length - 1);
            }

            if (parser.UseVerbose)
            {
                SyncSvcUtil.Log("Parsed ScopeName as {0}", scopeName);
            }

            // Its an CSDL document
            var dataServicesElem = document.Root.Element(Constants.SyncScopeDataServicesElement);

            if (dataServicesElem == null)
            {
                throw new CsdlException("No <DataServices> element found in the <edmx> document.");
            }
            var schemaElement = dataServicesElem.Element(Constants.SyncScopeSchemaElement);

            if (schemaElement == null)
            {
                throw new CsdlException("No <Schema> element found in the <DataServices> document.");
            }

            scopeDescription = new DbSyncScopeDescription(scopeName);
            // Loop over each <EntityType> element and add it as a DbSyncTableDescription
            foreach (var entity in schemaElement.Elements(Constants.SyncScopeEntityTypeElement))
            {
                var nameAttr = entity.Attribute(Constants.SyncScopeEntityTypeNameAttribute);
                if (nameAttr == null)
                {
                    throw new CsdlException("<EntityType> has no Name attribute. \n" + entity);
                }
                // Parse each entity and create a DbSyncTableDescription
                var table = new DbSyncTableDescription(nameAttr.Value);

                // Look for <Key> element
                var keyElem = entity.Element(Constants.SyncScopeEntityTypeKeyElement);
                if (keyElem == null)
                {
                    throw new CsdlException("<EntityType> has no <Key> elements defined. \n" + entity);
                }

                var keyNames = new List <string>();
                // Loop over each <PropertyRef> element and add it to the list for lookup
                foreach (var prop in keyElem.Elements(Constants.SyncScopeEntityTypeKeyRefElement))
                {
                    var keyName = prop.Attribute(Constants.SyncScopeEntityTypeNameAttribute);
                    if (keyName != null)
                    {
                        keyNames.Add(keyName.Value);
                    }
                }

                // Loop over each <Property> element and add it as a DbSyncColumnDescription
                foreach (var field in entity.Elements(Constants.SyncScopeEntityTypePropertyElement))
                {
                    // Read Property name
                    var fieldName = field.Attribute(Constants.SyncScopeEntityTypeNameAttribute);
                    if (fieldName == null)
                    {
                        throw new CsdlException("<Property> has no Name attribute. \n" + field);
                    }

                    // Read Property Edm type
                    var fieldType = field.Attribute(Constants.SyncScopeEntityTypeTypeAttribute);
                    if (fieldType == null)
                    {
                        throw new CsdlException("<Property> has no Type attribute. \n" + field);
                    }

                    // Read Property Nullable attribute
                    var fieldNullable = field.Attribute(Constants.SyncScopeEntityTypeNullableAttribute);

                    var column = new DbSyncColumnDescription(fieldName.Value, GetSqlTypeForEdm(fieldType.Value));
                    if (fieldNullable != null && bool.Parse(fieldNullable.Value))
                    {
                        column.IsNullable = true;
                    }
                    column.IsPrimaryKey = keyNames.Contains(fieldName.Value);
                    table.Columns.Add(column);
                }

                scopeDescription.Tables.Add(table);
            }
            return(scopeDescription);
        }