-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
92 changed files
with
14,810 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/src/bin | ||
/src/obj | ||
/tests/bin | ||
/tests/obj |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,13 @@ | ||
# xmla-client | ||
XMLA provider for a .NET Core OLAP client. | ||
# XMLA provider for a .NET Core OLAP client # | ||
|
||
Provides data access to any OLAP servers that support XMLA protocol and can be accessed over an HTTP connection. | ||
It is designed for development of an OLAP client in .NET Core applications that are completely independent of .NET Framework and therefore cannot use ADOMD.NET. | ||
|
||
### Approved OLAP servers ### | ||
|
||
* Microsoft Analysis Services (MD semantic model) | ||
* Mondrian | ||
|
||
### Requirements ### | ||
|
||
* .NET Core 2.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using System; | ||
using System.Linq; | ||
|
||
namespace RadarSoft.XmlaClient | ||
{ | ||
public static class ConnectionStringParser | ||
{ | ||
private static readonly string[] serverAliases = | ||
{ | ||
"server", "host", "data source", "datasource", "address", | ||
"addr", "network address" | ||
}; | ||
|
||
private static readonly string[] serverVersion = {"server version"}; | ||
private static readonly string[] databaseAliases = {"database", "initial catalog"}; | ||
private static readonly string[] usernameAliases = {"userid", "user id", "uid", "username", "user name", "user"}; | ||
private static readonly string[] passwordAliases = {"password", "pwd"}; | ||
|
||
public static string GetPassword(string connectionString) | ||
{ | ||
return GetValue(connectionString, passwordAliases); | ||
} | ||
|
||
public static string GetUsername(string connectionString) | ||
{ | ||
return GetValue(connectionString, usernameAliases); | ||
} | ||
|
||
public static string GetDatabaseName(string connectionString) | ||
{ | ||
return GetValue(connectionString, databaseAliases); | ||
} | ||
|
||
public static string GetDataSourceName(string connectionString) | ||
{ | ||
return GetValue(connectionString, serverAliases); | ||
} | ||
|
||
private static string GetValue(string connectionString, params string[] keyAliases) | ||
{ | ||
var keyValuePairs = connectionString.Split(';') | ||
.Where(kvp => kvp.Contains('=')) | ||
.Select(kvp => kvp.Split(new[] {'='}, 2)) | ||
.ToDictionary(kvp => kvp[0].Trim(), | ||
kvp => kvp[1].Trim(), | ||
StringComparer.CurrentCultureIgnoreCase); | ||
foreach (var alias in keyAliases) | ||
{ | ||
string value; | ||
if (keyValuePairs.TryGetValue(alias, out value)) | ||
return value.Trim('"'); | ||
} | ||
return string.Empty; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using System.Xml.Linq; | ||
using System.Xml.Serialization; | ||
using RadarSoft.XmlaClient.Metadata; | ||
using SimpleSOAPClient.Models; | ||
|
||
namespace RadarSoft.XmlaClient | ||
{ | ||
public static class Namespace | ||
{ | ||
/// <summary> | ||
/// Microsoft XML/A namespace | ||
/// </summary> | ||
public const string ComMicrosoftSchemasXmla = | ||
"urn:schemas-microsoft-com:xml-analysis"; | ||
|
||
public const string ComMicrosoftSchemasXmlaRowset = | ||
"urn:schemas-microsoft-com:xml-analysis:rowset"; | ||
|
||
public const string ComMicrosoftSchemasXmlaMddataset = | ||
"urn:schemas-microsoft-com:xml-analysis:mddataset"; | ||
} | ||
|
||
public static class XmlaPropertiesNames | ||
{ | ||
public const string TupleAxis_TupleFormat = "TupleFormat"; | ||
public const string Format_Tabular = "Tabular"; | ||
public const string Format_Multidimensional = "Multidimensional"; | ||
public const string Content_Data = "Data"; | ||
} | ||
|
||
/// <summary> | ||
/// Helper methods for working with <see cref="SoapEnvelope" /> instances. | ||
/// </summary> | ||
public static class EnvelopeHelpers | ||
{ | ||
public static IEnumerable<XElement> GetXRows(this SoapEnvelope envelope) | ||
{ | ||
return envelope.Body.Value.Descendants(XName.Get("row", Namespace.ComMicrosoftSchemasXmlaRowset)); | ||
} | ||
|
||
public static bool MamberUNameIs(this XElement xElement, string uniqName) | ||
{ | ||
return xElement.Descendants(XName.Get("MEMBER_UNIQUE_NAME", Namespace.ComMicrosoftSchemasXmlaRowset)) | ||
.FirstOrDefault()?.Value == uniqName; | ||
} | ||
|
||
public static string GetMamberUName(this XElement xElement) | ||
{ | ||
return xElement.Descendants(XName.Get("MEMBER_UNIQUE_NAME", Namespace.ComMicrosoftSchemasXmlaRowset)) | ||
.FirstOrDefault()?.Value; | ||
} | ||
|
||
public static XElement GetXOlapInfo(this SoapEnvelope envelope) | ||
{ | ||
return envelope.Body.Value.Descendants(XName.Get("OlapInfo", Namespace.ComMicrosoftSchemasXmlaMddataset)) | ||
.FirstOrDefault(); | ||
} | ||
|
||
public static IEnumerable<XElement> GetXCubes(XElement olapInfo) | ||
{ | ||
return olapInfo.Descendants(XName.Get("Cube", Namespace.ComMicrosoftSchemasXmlaMddataset)); | ||
} | ||
|
||
public static IEnumerable<XElement> GetXAxes(this SoapEnvelope envelope) | ||
{ | ||
return envelope.Body.Value.Descendants(XName.Get("Axis", Namespace.ComMicrosoftSchemasXmlaMddataset)); | ||
} | ||
|
||
public static IEnumerable<XElement> GetXCells(this SoapEnvelope envelope) | ||
{ | ||
return envelope.Body.Value.Descendants(XName.Get("Cell", Namespace.ComMicrosoftSchemasXmlaMddataset)); | ||
} | ||
|
||
public static IEnumerable<XElement> GetXTuples(XElement axis) | ||
{ | ||
return axis.Descendants(XName.Get("Tuple", Namespace.ComMicrosoftSchemasXmlaMddataset)); | ||
} | ||
|
||
public static IEnumerable<XElement> GetXMembers(XElement tuple) | ||
{ | ||
return tuple.Descendants(XName.Get("Member", Namespace.ComMicrosoftSchemasXmlaMddataset)); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Helper class with extensions for XML manipulation | ||
/// </summary> | ||
public static class XmlHelpers | ||
{ | ||
/// <summary> | ||
/// Deserializes a given XML string to a new object of the expected type. | ||
/// If null or white spaces the default(T) will be returned; | ||
/// </summary> | ||
/// <typeparam name="T">The type to be deserializable</typeparam> | ||
/// <param name="xml">The XML string to deserialize</param> | ||
/// <returns>The deserialized object</returns> | ||
public static T ToObject<T>(this string xml) | ||
{ | ||
if (string.IsNullOrWhiteSpace(xml)) return default(T); | ||
|
||
using (var textWriter = new StringReader(xml)) | ||
{ | ||
var result = (T) new XmlSerializer(typeof(T)).Deserialize(textWriter); | ||
|
||
return result; | ||
} | ||
} | ||
|
||
//public static async Task<T> ToXmlaObjectAsync<T>(this string xml) | ||
//{ | ||
// return await Task.Run(() => | ||
// { | ||
// if (string.IsNullOrWhiteSpace(xml)) return default(T); | ||
|
||
// using (var textWriter = new StringReader(xml)) | ||
// { | ||
// var result = (T)new XmlSerializer(typeof(T)).Deserialize(textWriter); | ||
|
||
// return result; | ||
// } | ||
// }); | ||
//} | ||
|
||
/// <summary> | ||
/// Deserializes a given <see cref="XElement" /> to a new object of the expected type. | ||
/// If null the default(T) will be returned. | ||
/// </summary> | ||
/// <typeparam name="T">The type to be deserializable</typeparam> | ||
/// <param name="xml">The <see cref="XElement" /> to deserialize</param> | ||
/// <returns>The deserialized object</returns> | ||
public static T ToObject<T>(this XElement xml, IXmlaBaseObject owner = null) where T : IXmlaBaseObject | ||
{ | ||
var xstr = xml.ToString(); | ||
if (string.IsNullOrWhiteSpace(xstr)) return default(T); | ||
|
||
using (var textWriter = new StringReader(xstr)) | ||
{ | ||
var result = (T)new XmlSerializer(typeof(T)).Deserialize(textWriter); | ||
|
||
result.SoapRow = xml; | ||
if (owner != null) | ||
{ | ||
result.Connection = owner.Connection; | ||
result.CubeName = owner.CubeName; | ||
result.ParentObject = owner; | ||
} | ||
|
||
return result; | ||
} | ||
} | ||
|
||
public static async Task<T> ToXmlaObjectAsync<T>(this XElement xml, IXmlaBaseObject owner = null) where T : IXmlaBaseObject | ||
{ | ||
return await Task.Run(() => | ||
{ | ||
var xstr = xml.ToString(); | ||
if (string.IsNullOrWhiteSpace(xstr)) return default(T); | ||
|
||
using (var textWriter = new StringReader(xstr)) | ||
{ | ||
var result = (T)new XmlSerializer(typeof(T)).Deserialize(textWriter); | ||
|
||
result.SoapRow = xml; | ||
if (owner != null) | ||
{ | ||
result.Connection = owner.Connection; | ||
result.CubeName = owner.CubeName; | ||
result.ParentObject = owner; | ||
} | ||
return result; | ||
} | ||
}); | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
namespace RadarSoft.RadarCube.XmlaClient | ||
{ | ||
using System; | ||
using System.Data; | ||
using System.Xml; | ||
|
||
/// <summary> | ||
/// Interface for XmlaCommand. | ||
/// </summary> | ||
public interface IXmlaCommand : IDbCommand | ||
{ | ||
/// <summary> | ||
/// Creates a data adapter associated with the command. | ||
/// Command is used as SelectCommand. | ||
/// </summary> | ||
/// <returns>The data adapter.</returns> | ||
IXmlaDataAdapter CreateDataAdapter(); | ||
|
||
/// <summary> | ||
/// Runs the AdomdCommand, and returns either a CellSet or an AdomdDataReader. | ||
/// </summary> | ||
/// <returns>An object.</returns> | ||
/// <exception cref="AdomdErrorResponseException">The provider returned an error in response.</exception> | ||
/// <exception cref="AdomdUnknownResponseException">The provider sent an unrecognizable response.</exception> | ||
/// <exception cref="AdomdConnectionException">The provider sent an unrecognizable response.</exception> | ||
/// <exception cref="InvalidOperationException">An error occurred because one of the following conditions was met: | ||
/// - The connection was not set. | ||
/// - The connection was not opened. | ||
/// - Either the CommandText property or the CommandStream property was improperly set. | ||
/// - Both the CommandText property and the CommandStream property were set. | ||
/// - Neither the CommandText property, nor the CommandStream property, was set. | ||
/// </exception> | ||
/// <remarks> | ||
/// The Execute method tries to run the command that is contained by the AdomdCommand. | ||
/// Depending on the format of the results returned by the provider, the Execute method returns either an AdomdDataReader or a CellSet. | ||
/// If the results cannot be formatted into either an AdomdDataReader or a CellSet, or if the provider returned no results, the method returns a null value. | ||
/// </remarks> | ||
object Execute(); | ||
|
||
/// <summary> | ||
/// Runs the AdomdCommand and returns a CellSet. | ||
/// </summary> | ||
/// <returns>The cell set.</returns> | ||
/// <exception cref="AdomdErrorResponseException">The provider returned an error in response.</exception> | ||
/// <exception cref="AdomdUnknownResponseException">The provider sent an unrecognizable response.</exception> | ||
/// <exception cref="AdomdConnectionException">The provider sent an unrecognizable response.</exception> | ||
/// <exception cref="InvalidOperationException">An error occurred because one of the following conditions was met: | ||
/// - The connection was not set. | ||
/// - The connection was not opened. | ||
/// - Either the CommandText property or the CommandStream property was improperly set. | ||
/// - Both the CommandText property and the CommandStream property were set. | ||
/// - Neither the CommandText property, nor the CommandStream property, was set. | ||
/// </exception> | ||
/// <remarks> | ||
/// The ExecuteCellSet method tries to run the command that is contained by the AdomdCommand and returns a CellSet that contains the results of the command. | ||
/// If the provider does not return a valid analytical data set, an exception is thrown. | ||
/// </remarks> | ||
CellSet ExecuteCellSet(); | ||
|
||
/// <summary> | ||
/// Runs the AdomdCommand and returns an XmlReader. | ||
/// </summary> | ||
/// <returns>An XmlReaderthat contains the results of the command.</returns> | ||
/// <exception cref="AdomdErrorResponseException">The provider returned an error in response.</exception> | ||
/// <exception cref="AdomdUnknownResponseException">The provider sent an unrecognizable response.</exception> | ||
/// <exception cref="AdomdConnectionException">The provider sent an unrecognizable response.</exception> | ||
/// <exception cref="InvalidOperationException">An error occurred because one of the following conditions was met: | ||
/// - The connection was not set. | ||
/// - The connection was not opened. | ||
/// - Either the CommandText property or the CommandStream property was improperly set. | ||
/// - Both the CommandText property and the CommandStream property were set. | ||
/// - Neither the CommandText property, nor the CommandStream property, was set. | ||
/// </exception> | ||
/// <remarks> | ||
/// Instead of translating the XML for Analysis response from an XML format into an AdomdDataReader or CellSet, this method, returns an XmlReader that directly references the XML for Analysis response in its native XML format. | ||
/// While the XmlReaderis in use, the associated AdomdConnection is busy serving the XmlReader. While in this state, the AdomdConnection can only be closed; no other operations can be performed on it. This remains the case until the Close method of the XmlReaderis called. | ||
/// You should be prepared to catch any exception that can be thrown while using the XmlReader, such as the XmlException. | ||
/// </remarks> | ||
XmlReader ExecuteXmlReader(); | ||
} | ||
} |
Oops, something went wrong.