public void ProcessRequest(HttpContext context) { if (!this.IsHttpGet(context)) { this.RespondForbidden(context); } else { if (OgdiAlias.ToLower() != "sql") { context.Response.Write("Endpoint '" + OgdiAlias + "' does not exist."); context.Response.StatusCode = 404;//internal server error (int)response.StatusCode; context.Response.End(); return; } //context.Response.Headers["DataServiceVersion"] = "1.0;"; context.Response.AddHeader("DataServiceVersion", "1.0;"); context.Response.CacheControl = "no-cache"; context.Response.ContentType = "application/xml;charset=utf-8"; var xmlBase = "http://" + context.Request.Url.Host + context.Request.Url.AbsolutePath; try { var sql = sqlServerConnection.GetDataServiceInstance(); var reader = sql.GetReader( @"SELECT EntitysetName FROM odpdataservicemetadata;"); //var tables = sql.GetTables(); context.Response.Write(string.Format(START_SERVICEDOCUMENT_TEMPLATE, xmlBase)); foreach (DataRow row in reader.Rows) { context.Response.Write(string.Format(COLLECTION_TEMPLATE, row["EntitysetName"].ToString())); } context.Response.Write(END_SERVICEDOCUMENT_TEMPLATE); } catch (Exception ex) { context.Response.Write(ex.Message); context.Response.StatusCode = 500;//internal server error (int)response.StatusCode; context.Response.End(); string sSource; string sLog; string sEvent; sSource = "ODP API"; sLog = "Application"; sEvent = ex.Message; if (!System.Diagnostics.EventLog.SourceExists(sSource)) { System.Diagnostics.EventLog.CreateEventSource(sSource, sLog); } System.Diagnostics.EventLog.WriteEntry(sSource, sEvent); System.Diagnostics.EventLog.WriteEntry(sSource, sEvent, System.Diagnostics.EventLogEntryType.Warning, 234); } } }
private void ReplaceAzureNamespaceInCategoryTermValue(XElement entry) { // use the simple approach of representing "entitykind" as // "entityset" value plus the text "Item." A decision was made to do // this at the service level for now so that we wouldn't have to deal // with changing the data import code and the existing values in the // EntityMetadata table. var term = entry.Element(_categoryXName).Attribute("term"); //TODO: apply real fix. OgdiAlias is null for AvailableEndpoints if (OgdiAlias == null) { return; } if (_entityKind == null) { string termValue = term.Value; int dotLocation = termValue.IndexOf("."); string entitySet = termValue.Substring(dotLocation + 1); _entityKind = LoadEntityKind(_context, entitySet); } term.Value = string.Format(_termNamespaceString, OgdiAlias.ToLower(), _entityKind); }
public void ProcessRequest(HttpContext context) { _entityKind = null; if (!this.IsHttpGet(context)) { this.RespondForbidden(context); } else { if (OgdiAlias.ToLower() != "sql") { context.Response.Write("Endpoint '" + OgdiAlias + "' does not exist."); context.Response.StatusCode = 404;//internal server error (int)response.StatusCode; context.Response.End(); return; } _context = context; try { var sql = sqlServerConnection.GetDataServiceInstance(); _filter = _context.Request.QueryString["$filter"]; string top = _context.Request.QueryString["$top"]; string skip = _context.Request.QueryString["$skip"]; string columns = _context.Request.QueryString["$select"]; string order = _context.Request.QueryString["$orderby"]; int ntop = -1; int nskip = 0; if (!string.IsNullOrEmpty(top)) { try { ntop = Convert.ToInt32(top); } catch { } } if (!string.IsNullOrEmpty(skip)) { try { nskip = Convert.ToInt32(skip); } catch { } } string format = _context.Request.QueryString["format"]; if (!string.IsNullOrEmpty(format)) { format = format.ToLower(); } _context.Response.AddHeader("DataServiceVersion", "1.0;"); _context.Response.CacheControl = "no-cache"; _context.Response.AddHeader("x-ms-request-id", "-1");//TODO what ID should I use??? if (format == "kml") { RenderKml(sql /*, longlatCols, kmlCol*/); } else { //for both atom and json the starting point is OData //but for atom we should feed directly to the response //this means responsive GUI even with large data feeds //bool odata = format != "json"; //these are really not next values, we're interested in values greater than, the naming remains from azure nomenclature var nextPartKey = _context.Request.QueryString["NextPartitionKey"]; var nextRowKey = _context.Request.QueryString["NextRowKey"]; _entitySet = _entitySet.Replace("()", ""); string wholeXml = string.Format(START_SERVICEDOCUMENT_TEMPLATE, _context.Request.Url.Host, _ogdiAlias, _entitySet); var md = sql.sqlGetEntitySetMetaData(_entitySet); bool isRowId = !string.IsNullOrEmpty(md.RowId); var sql2 = sqlServerConnection.GetDataServiceInstance(); DataTable reader = sql2.GetReader(md, columns, _filter, ntop, nextRowKey, nskip, order); //for easy string comparison ... md.Longitude = md.Longitude.ToLower(); md.Latitude = md.Latitude.ToLower(); md.KmlSnippet = md.KmlSnippet.ToLower(); //this is not OData friendly, but... //when columns are specified as containing KML data we don't show them because //1. kml is not OData, it must be fed via format=kml //2. some kml snippets could be very large //string[] cols = (longlatCols ?? "").ToLower().Split(',');//we //string col = (kmlCol ?? "").ToLower(); var fmt = new NumberFormatInfo() { NumberDecimalSeparator = "." }; int read = 0; string partitionKey = ""; //unused string rowKey = ""; //read if defined in the metadata - we're interested in the last one, but we read all of them StringBuilder sb = new StringBuilder(wholeXml); foreach (DataRow row in reader.Rows) { read++; string properties = ""; properties += string.Format(PROPERTY_TEMPLATE, "PartitionKey", string.Empty, ""); properties += string.Format(PROPERTY_TEMPLATE, "RowKey", string.Empty, ""); for (int i = 0; i < reader.Columns.Count; i++) { string name = reader.Columns[i].ColumnName; string lName = name.ToLower(); if (lName == md.KmlSnippet) { continue;//exclude } Type type = row[i].GetType(); string val = row[i].ToString(); string key = string.Empty; string valType = string.Empty; if (!Convert.IsDBNull(row[i])) { if (type == typeof(double)) { val = Convert.ToDouble(row[i]).ToString(fmt); } else if (type == typeof(decimal)) { val = Convert.ToDecimal(row[i]).ToString(fmt); } else if (type == typeof(DateTime)) { val = Convert.ToDateTime(row[i]).ToString("yyyy-MM-dd'T'HH:mm:ss.fffffffZ"); valType = " " + "m:type=\"Edm.DateTime\""; } else { val = row[i].ToString(); } key = val; if (type == typeof(string)) { val = "<![CDATA[" + val + "]]>"; } } properties += string.Format(PROPERTY_TEMPLATE, name, valType, val); if (isRowId) { if (name == md.RowId) { rowKey = key; } } } string entry = string.Format(ENTRY_TEMPLATE, context.Request.Url.Host, _ogdiAlias, _entitySet, properties, partitionKey, rowKey); sb.Append(entry); } wholeXml = sb.ToString(); sb.Clear(); sb = null; wholeXml += END_SERVICEDOCUMENT_TEMPLATE; if (read == ntop) //there is still data left to be read, continue paging { //sl-king //Azure seems to use two keys to identify a row - PartitionKey and RowKey (it doesn't really matter here) //the Interactive SDK uses both to support data paging //with SQL server we use only RowKey and for the PartitionKey just use "dummy" value just to enable paging //string continuationNextPartitionKey = response.Headers["x-ms-continuation-NextPartitionKey"]; //if (continuationNextPartitionKey != null) { _context.Response.AddHeader("x-ms-continuation-NextPartitionKey", "dummy");//continuationNextPartitionKey } //string continuationNextRowKey = response.Headers["x-ms-continuation-NextRowKey"]; //if (continuationNextRowKey != null) { _context.Response.AddHeader("x-ms-continuation-NextRowKey", rowKey);//continuationNextRowKey } } if (format == "json") { _context.Response.ContentType = "application/json"; var xml = XElement.Parse(wholeXml); this.RenderJson(xml); } else { _context.Response.ContentType = "application/atom+xml;charset=utf-8"; _context.Response.Write(wholeXml); } } if (true)//TODO implement { } else//TODO implement kml and json { } } catch (Exception ex) { Odp.Data.ErrorLog.WriteError(ex.Message); } } }
public void ProcessRequest(HttpContext context) { if (!this.IsHttpGet(context)) { this.RespondForbidden(context); } else { context.Response.AddHeader("DataServiceVersion", "1.0;"); context.Response.CacheControl = "no-cache"; context.Response.ContentType = "application/xml;charset=utf-8"; if (OgdiAlias.ToLower() != "sql") { context.Response.Write("Endpoint '" + OgdiAlias + "' does not exist."); context.Response.StatusCode = 404;//internal server error (int)response.StatusCode; context.Response.End(); return; } try { context.Response.Write(string.Format(START_DATASERVICES_TEMPLATE, this.OgdiAlias.ToLower())); var sql = sqlServerConnection.GetDataServiceInstance(); var metadata = sql.GetTablesMetadata(/*filter,*/ "", true); //overview of all EntitySets foreach (var data in metadata) { context.Response.Write(string.Format(ENTITYSET_TEMPLATE, data.name, this.OgdiAlias, data.name + "Item")); } context.Response.Write(END_ENTITYCONTAINER_TEMPLATE); //these are properties from the template which we'll ignore if found string[] fields = new string[] { "PartitionKey", "RowKey" };//, "Timestamp", "entityid"}; //a detailed data for each EntitySet foreach (var data in metadata) { context.Response.Write(string.Format(START_ENTITYTYPE_TEMPLATE, data.name + "Item")); foreach (var pdata in data.properties) { //to be able to work with prepared templates //we have to get rid of entityid, which doesn't exist if (fields.Any(s => s.Equals(pdata.name))) { continue; } context.Response.Write(string.Format(START_PROPERTY_TEMPLATE, pdata.name, pdata.dataType, pdata.nullable)); } context.Response.Write(END_ENTITYTYPE_TEMPLATE); } context.Response.Write(END_ENTITYTYPESCHEMA_TEMPLATE); context.Response.Write(END_DATASERVICES_TEMPLATE); } catch (Exception ex) { Odp.Data.ErrorLog.WriteError(ex.Message); } } }