diff Source/ServiceModel/LinqService.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Source/ServiceModel/LinqService.cs	Thu Mar 27 21:46:09 2014 +0400
@@ -0,0 +1,272 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.ServiceModel;
+using System.Web.Services;
+
+namespace BLToolkit.ServiceModel
+{
+	using Data;
+	using Data.Linq;
+	using Data.Sql;
+
+	[ServiceBehavior  (InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
+	[WebService       (Namespace  = "http://tempuri.org/")]
+	[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
+	public class LinqService : ILinqService
+	{
+		public LinqService()
+		{
+		}
+
+		public LinqService(string configuration)
+		{
+			Configuration = configuration;
+		}
+
+		public string Configuration { get; set; }
+		public bool   AllowUpdates  { get; set; }
+
+		public static Func<string,Type> TypeResolver = _ => null;
+
+		public virtual IDataContext CreateDataContext()
+		{
+			return Settings.CreateDefaultDataContext(Configuration);
+		}
+
+		protected virtual void ValidateQuery(LinqServiceQuery query)
+		{
+			if (AllowUpdates == false && !query.Query.IsSelect)
+				throw new LinqException("Insert/Update/Delete requests are not allowed by the service policy.");
+		}
+
+		protected virtual void HandleException(Exception exception)
+		{
+		}
+
+		#region ILinqService Members
+
+		public Type SqlProviderType { get; set; }
+
+		[WebMethod]
+		public virtual string GetSqlProviderType()
+		{
+			try
+			{
+				if (SqlProviderType == null)
+					using (var ctx = CreateDataContext())
+						SqlProviderType = ctx.CreateSqlProvider().GetType();
+
+				return SqlProviderType.FullName;
+			}
+			catch (Exception exception)
+			{
+				HandleException(exception);
+				throw;
+			}
+		}
+
+		class QueryContext : IQueryContext
+		{
+			public SqlQuery       SqlQuery   { get; set; }
+			public object         Context    { get; set; }
+			public SqlParameter[] Parameters { get; set; }
+
+			public SqlParameter[] GetParameters()
+			{
+				return Parameters;
+			}
+		}
+
+		[WebMethod]
+		public int ExecuteNonQuery(string queryData)
+		{
+			try
+			{
+				var query = LinqServiceSerializer.Deserialize(queryData);
+
+				ValidateQuery(query);
+
+				using (var db = CreateDataContext())
+				{
+					var obj = db.SetQuery(new QueryContext { SqlQuery = query.Query, Parameters = query.Parameters });
+					return db.ExecuteNonQuery(obj);
+				}
+			}
+			catch (Exception exception)
+			{
+				HandleException(exception);
+				throw;
+			}
+		}
+
+		[WebMethod]
+		public object ExecuteScalar(string queryData)
+		{
+			try
+			{
+				var query = LinqServiceSerializer.Deserialize(queryData);
+
+				ValidateQuery(query);
+
+				using (var db = CreateDataContext())
+				{
+					var obj = db.SetQuery(new QueryContext { SqlQuery = query.Query, Parameters = query.Parameters });
+					return db.ExecuteScalar(obj);
+				}
+			}
+			catch (Exception exception)
+			{
+				HandleException(exception);
+				throw;
+			}
+		}
+
+		[WebMethod]
+		public string ExecuteReader(string queryData)
+		{
+			try
+			{
+				var query = LinqServiceSerializer.Deserialize(queryData);
+
+				ValidateQuery(query);
+
+				using (var db = CreateDataContext())
+				{
+					var obj = db.SetQuery(new QueryContext { SqlQuery = query.Query, Parameters = query.Parameters });
+
+					using (var rd = db.ExecuteReader(obj))
+					{
+						var ret = new LinqServiceResult
+						{
+							QueryID    = Guid.NewGuid(),
+							FieldCount = rd.FieldCount,
+							FieldNames = new string[rd.FieldCount],
+							FieldTypes = new Type  [rd.FieldCount],
+							Data       = new List<string[]>(),
+						};
+
+						for (var i = 0; i < ret.FieldCount; i++)
+						{
+							ret.FieldNames[i] = rd.GetName(i);
+							ret.FieldTypes[i] = rd.GetFieldType(i);
+						}
+
+						var varyingTypes = new List<Type>();
+
+						while (rd.Read())
+						{
+							var data  = new string  [rd.FieldCount];
+							var codes = new TypeCode[rd.FieldCount];
+
+							for (var i = 0; i < ret.FieldCount; i++)
+								codes[i] = Type.GetTypeCode(ret.FieldTypes[i]);
+
+							ret.RowCount++;
+
+							for (var i = 0; i < ret.FieldCount; i++)
+							{
+								if (!rd.IsDBNull(i))
+								{
+									var code = codes[i];
+									var type = rd.GetFieldType(i);
+									var idx = -1;
+
+									if (type != ret.FieldTypes[i])
+									{
+										code = Type.GetTypeCode(type);
+										idx  = varyingTypes.IndexOf(type);
+
+										if (idx < 0)
+										{
+											varyingTypes.Add(type);
+											idx = varyingTypes.Count - 1;
+										}
+									}
+
+									switch (code)
+									{
+										case TypeCode.Decimal  : data[i] = rd.GetDecimal (i).ToString(CultureInfo.InvariantCulture); break;
+										case TypeCode.Double   : data[i] = rd.GetDouble  (i).ToString(CultureInfo.InvariantCulture); break;
+										case TypeCode.Single   : data[i] = rd.GetFloat   (i).ToString(CultureInfo.InvariantCulture); break;
+										case TypeCode.DateTime : data[i] = rd.GetDateTime(i).ToString("o");                          break;
+										default                :
+											{
+												if (type == typeof(DateTimeOffset))
+												{
+													var dt = rd.GetValue(i);
+
+													if (dt is DateTime)
+														data[i] = ((DateTime)dt).ToString("o");
+													else if (dt is DateTimeOffset)
+														data[i] = ((DateTimeOffset)dt).ToString("o");
+													else
+														data[i] = rd.GetValue(i).ToString();
+												}
+												else if (ret.FieldTypes[i] == typeof(byte[]))
+													data[i] = Convert.ToBase64String((byte[])rd.GetValue(i));
+												else
+													data[i] = (rd.GetValue(i) ?? "").ToString();
+
+												break;
+											}
+									}
+
+									if (idx >= 0)
+										data[i] = "\0" + (char)idx + data[i];
+								}
+							}
+
+							ret.Data.Add(data);
+						}
+
+						ret.VaryingTypes = varyingTypes.ToArray();
+
+						return LinqServiceSerializer.Serialize(ret);
+					}
+				}
+			}
+			catch (Exception exception)
+			{
+				HandleException(exception);
+				throw;
+			}
+		}
+
+		[WebMethod]
+		public int ExecuteBatch(string queryData)
+		{
+			try
+			{
+				var data    = LinqServiceSerializer.DeserializeStringArray(queryData);
+				var queries = data.Select<string,LinqServiceQuery>(LinqServiceSerializer.Deserialize).ToArray();
+
+				foreach (var query in queries)
+					ValidateQuery(query);
+
+				using (var db = CreateDataContext())
+				{
+					if (db is DbManager) ((DbManager)db).BeginTransaction();
+
+					foreach (var query in queries)
+					{
+						var obj = db.SetQuery(new QueryContext { SqlQuery = query.Query, Parameters = query.Parameters });
+						db.ExecuteNonQuery(obj);
+					}
+
+					if (db is DbManager) ((DbManager)db).CommitTransaction();
+
+					return queryData.Length;
+				}
+			}
+			catch (Exception exception)
+			{
+				HandleException(exception);
+				throw;
+			}
+		}
+
+		#endregion
+	}
+}