WCF Data Service: Bad Request - Error in query syntax - c#

I have WCF Data Service application. The back-end database is Ingress and it uses nHibernate.
I am trying to fetch and update records from one of the tables. Its structure is given here under:
First three highlighted columns make primary key.
In my client application I am querying the data like below:
private void LoadItemDetails(string itemCode, int commentDate)
{
using(var dc = new MyDataContext(new Uri("http://myservice.myserver.com/Dev/com.OData/IngressData.svc")))
{
var itemDetails = dc
.ItemLineDetails
.Where(d => d.ItemCode.Equals(itemCode) &&
ld.CommentDate == commentDate);
ObsItemLineDetails = new ObservableCollection<ItemLineDets>();
}
}
Then I update and save the data as shown below:
private void SaveItemDetails()
{
using(var dc = new MyDataContext(new Uri("http://myservice.myserver.com/Dev/com.OData/IngressData.svc")))
{
foreach(var itemLine in ObsItemLineDetails )
{
var today = DateTime.Today.AddSeconds(-1);
var newCommentDate = (Int32)(today.Subtract(new DateTime(1970, 1, 1,0,0,0))).TotalSeconds;
var itemDetail = dc.ItemLineDetails.Where(d => d.ItemCode.Equals(itemLine.ItemCode) &&
d.LineId == itemLine.LineId &&
d.SearchDate == itemLine.SearchDate).FirstOrDefault();
if (itemDetail != null)
{
itemDetail.CommentDate = newCommentDate;
itemDetail.Comments = GetAutoComment();
dc.UpdateObject(itemDetail);
}
}
dc.SaveChanges();
}
}
It raises an exception on the last line when SaveChanges is being called. Following is the IIS server log entry.
15:52:42.7823 Trace 20 com.OData.DataServiceBase`1 Received: http://myservice.myserver.com/Dev/com.OData/IngressData.svc/ItemLineDetails(ItemCode='001/152/0101',LineId=3,SearchDate=11070945856)
15:52:42.7823 Error 20 com.OData.DataServiceBase`1 Bad Request - Error in query syntax.
at System.Data.Services.RequestUriProcessor.ParsePath(Uri absoluteRequestUri, IDataService service)
at System.Data.Services.RequestUriProcessor.ProcessRequestUri(Uri absoluteRequestUri, IDataService service, Boolean internalQuery)
at System.Data.Services.DataService`1.HandleRequest() at System.Data.Services.RequestUriProcessor.ParsePath(Uri absoluteRequestUri, IDataService service)
at System.Data.Services.RequestUriProcessor.ProcessRequestUri(Uri absoluteRequestUri, IDataService service, Boolean internalQuery)
at System.Data.Services.DataService`1.HandleRequest()
I think its probably the forward slashes in my ITEM_CODE field causing this problem.
If that's the case, is there any workaround for this.

try to add using on DataContext in the function instead of a global context object
like below
private void SaveItemDetails()
{
using(context dc = new context())
{
foreach(var itemLine in ObsItemLineDetails )
{
var today = DateTime.Today.AddSeconds(-1);
var newCommentDate = (Int32)(today.Subtract(new DateTime(1970, 1, 1,0,0,0))).TotalSeconds;
var itemDetail = dc.ItemLineDetails.Where(d => d.ItemCode.Equals(itemLine.ItemCode) &&
d.LineId == itemLine.LineId &&
d.SearchDate == itemLine.SearchDate).FirstOrDefault();
if (itemDetail != null)
{
itemDetail.CommentDate = newCommentDate;
itemDetail.Comments = GetAutoComment();
dc.UpdateObject(itemDetail);
}
}
dc.SaveChanges();
}
}

Related

How to optimize CRUD operation in EF using DBContext?

I have a function which grabs the data from API and stores into the database.
public async Task GetApps()
{
var request = new HttpRequestMessage(HttpMethod.Get, "apps?per_page=200");
var response = await _client_SB.SendAsync(request);
var json = await response.Content.ReadAsStringAsync();
AppsClass.AppsRootobject model = JsonConvert.DeserializeObject<AppsClass.AppsRootobject>(json);
using (var scope = _scopeFactory.CreateScope())
{
var _DBcontext = scope.ServiceProvider.GetRequiredService<PCFStatusContexts>();
foreach (var item in model.resources)
{
var g = Guid.Parse(item.guid);
var x = _DBcontext.Apps.FirstOrDefault(o => o.AppGuid == g);
if (x == null)
{
_DBcontext.Apps.Add(new Apps
{
AppGuid = Guid.Parse(item.guid),
Name = item.name,
State = item.state,
CreatedAt = item.created_at,
UpdatedAt = item.updated_at,
SpaceGuid = Guid.Parse(item.relationships.space.data.guid),
Foundation = 2,
Timestamp = DateTime.Now
});
}
else if (x.UpdatedAt != item.updated_at)
{
x.State = item.state;
x.CreatedAt = item.created_at;
x.UpdatedAt = item.updated_at;
x.Timestamp = DateTime.Now;
}
var guids = model.resources.Select(r => Guid.Parse(r.guid));
var apps = _DBcontext.Apps.Where(o => guids.Contains(o.AppGuid) == false && o.Foundation == 2);
foreach (var app in apps)
{
app.DeletedAt = DateTime.Now;
}
}
await _DBcontext.SaveChangesAsync();
}
}
The above function works just fine except the snippet for DeletedAt
var guids = model.resources.Select(r => Guid.Parse(r.guid));
var apps = _DBcontext.Apps.Where(o => guids.Contains(o.AppGuid) == false && o.Foundation == 2);
foreach (var app in apps)
{
app.DeletedAt = DateTime.Now;
}
it's not like it doesn't work at all but when the GetApps function called every second because of this snippet I'm getting the following error
An exception occurred while iterating over the results of a query for
context type 'TestApp.Context.DBContexts'.
System.InvalidOperationException: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This
may have occurred because all pooled connections were in use and max
pool size was reached.
If I remove DeletedAt snippet it works just fine but I need that functionality, is there any way to optimize this? can I make it async?

API is mixing up data from different devices

I have an API that has devices firing data to it at the same time or within a few milliseconds. What I am finding is that the data is getting mixed up. The data is sent every five minutes (on the clock 05, 10, 15 etc.) I have an execution filter that traps the URL data coming in so I always have a real source, then it goes to the endpoint and then onto processing. For example, there will a be random five minute period missing. When I debug step by step with the missing URL from the execution filter it works fine. By that I mean I take the URL and debug, then it inserts.
In summary, I have device id 1 and device id 2.I will get missing intervals even though, I can see the data has hit the execution filter.
I am assuming that the API is not handling these as separate transactions, but somehow mixing them up together, hence the data missing and the serial numbers appearing in the wrong place, such that data from id 1 is appearing in id 2 vice versa etc.
API End Point:
public class SomeController : ApiController
{
[HttpGet]
[ExecutionFilter]
public async Task<HttpResponseMessage> Get([FromUri] FixedDataModel fdm)
{
var reply = new HttpResponseMessage();
string url = HttpUtility.UrlDecode(HttpContext.Current.Request.QueryString.ToString());
if (url.Contains("timestamp"))
{
reply = TimeSyncValidation.TimeSync;
return reply;
}
else if (!url.Contains("timestamp"))
{
reply = await Task.Run(() => DeviceClass.DeviceApiAsync(fdm, url));
}
return reply;
}
}
Processing class:
namespace API.Services
{
public class DeviceClass
{
private static string serialNumber;
private static byte chk;
private static string channelName, channelReadingNumber, channelValue, queryString, readingDate;
private static int colonPosition, chanCountFrom, equalsPosition;
private static bool checkSumCorrect;
public static HttpResponseMessage DeviceApiAsync(FixedDataModel fdm, string urlQqueryString)
{
Guid guid = Guid.NewGuid();
//ExecutionTrackerHandler.Guid = guid;
//Remove question mark
var q = urlQqueryString;
queryString = q.Substring(0);
var items = HttpUtility.ParseQueryString(queryString);
serialNumber = items["se"];
//Store raw uri for fault finding
var rawUri = new List<RawUriModel>
{
new RawUriModel
{
UniqueId = guid,
RawUri = q,
TimeStamp = DateTime.Now
}
};
//Checksum validation
chk = Convert.ToByte(fdm.chk);
checkSumCorrect = CheckSumValidator.XorCheckSum(queryString, chk);
if (!checkSumCorrect)
{
return ValidationResponseMessage.ResponseHeaders("Checksum");
}
//Create list of items that exist in URL
var urldata = new UrlDataList
{
UrlData = queryString.Split('&').ToList(),
};
var data = new List<UriDataModel>();
//Split the URL string into its parts
foreach (var item in urldata.UrlData)
{
colonPosition = item.IndexOf(":");
chanCountFrom = colonPosition + 1;
equalsPosition = item.LastIndexOf("=");
if (colonPosition == -1)
{
channelName = item.Substring(0, equalsPosition);
channelReadingNumber = "";
channelValue = item.Substring(item.LastIndexOf("=") + 1);
}
else
{
channelName = item.Substring(0, colonPosition);
channelReadingNumber = item.Substring(chanCountFrom, equalsPosition - chanCountFrom);
channelValue = item.Substring(item.LastIndexOf("=") + 1);
if (channelName == "atime" || channelName == "adate")
{
readingDate = DateValidator.CreateDate(channelValue);
}
};
bool nullFlag = false;
if (channelValue == null)
nullFlag = true;
bool missingFlag = false;
if (channelValue == "x") {
missingFlag = true;
channelValue = "0";
}
//Add data to model ready for DB insert.
data.Add(new UriDataModel
{
uid = guid,
SerialNumber = serialNumber,
ChannelName = channelName,
ChannelReadingNumber = channelReadingNumber,
ChannelValue = channelValue.Replace(",", "."),
ReadingDate = readingDate,
TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm"),
Processed = false,
NullFlag = nullFlag,
MissingFlag = missingFlag
});
};
//Validate dates
var allDates = (from x in data where x.ChannelName.Contains("atime") || x.ChannelName.Contains("adate") select x.ChannelValue).ToList();
bool dateValidation = DateValidator.IsValid(allDates);
if (!dateValidation)
{
return ValidationResponseMessage.ResponseHeaders("Date");
};
//Validate values
var channels = Enum.GetNames(typeof(Channels)).ToList();
List<string> allChannelValues = data.Where(d => channels.Contains(d.ChannelName)).Select(d => d.ChannelValue).ToList();
bool valueValidation = ValueValidator.IsValid(allChannelValues);
if (!valueValidation)
{
return ValidationResponseMessage.ResponseHeaders("Values");
};
//Insert live data
var insertData = DataInsert<UriDataModel>.InsertData(data, "Staging.UriData");
if (!insertData)
{
return ValidationResponseMessage.ResponseHeaders("Sql");
}
var content = "\r\nSUCCESS\r\n";
var reply = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
{
Content = new StringContent(content)
};
return reply;
}
}
}
TIA
You are using global variables and static method to process your data.
Change your method to non-static.
Each DeviceClass worker must update only its own isolated data then push that off back to controller.

WCF Websocket project fails upon Entity Framework data access attempt

I am new to WebSockets (this AM) and have set up a WCF WebSocket app that works when doing a trivial example I found online (http://www.codeproject.com/Articles/619343/Using-WebSocket-in-NET-Part).
I added Entity Framework and as soon as I add code to try to access data the process (just sending a message back and forth) no longer works.
Could there be some fundamental concept I could be missing?
Does anyone have any good ideas for troubleshooting?
namespace PBWebSocket
{
public class PBWebSocket : IBWebSocket
{
private SPEntities db = new SPEntities();
public async Task SendMessageToServer(Message msg)
{
var callback = OperationContext.Current.GetCallbackChannel<IPBCallback>();
if (msg.IsEmpty || ((IChannel)callback).State != CommunicationState.Opened)
{
return;
}
byte[] body = msg.GetBody<byte[]>();
string msgTextFromClient = Encoding.UTF8.GetString(body);
var reqId = Int32.Parse(msgTextFromClient);
// *** The below line breaks it ***
var req = db.Requests.Where(r => r.Id == 164).FirstOrDefault();
reqId = reqId + 2;
Message newMsg = ByteStreamMessage.CreateMessage(
new ArraySegment<byte>(Encoding.UTF8.GetBytes(reqId.ToString())));
newMsg.Properties["WebSocketMessageProperty"] =
new WebSocketMessageProperty
{ MessageType = WebSocketMessageType.Text };
await callback.SendMessageToClient(newMsg);
}
}
}

The underlying provider failed on Open / The operation is not valid for the state of the transaction

Here is my code
public static string UpdateEmptyCaseRevierSet() {
string response = string.Empty;
using (System.Transactions.TransactionScope tran = new System.Transactions.TransactionScope()) {
using (var db = new Entities.WaveEntities()) {
var maxCaseReviewersSetID = db.CaseReviewerSets.Select(crs => crs.CaseReviewersSetId).Max();
var emptyCHList = db.CaseHistories.Where(ch => ch.CaseReviewersSetID == null && ch.IsLatest == true && ch.StatusID != 100).ToList();
for(int i=0; i < emptyCHList.Count; i++) {
var emptyCH = emptyCHList[i];
var newCaseReviewerSET = new Entities.CaseReviewerSet();
newCaseReviewerSET.CreationCHID = emptyCH.CHID;
db.CaseReviewerSets.Add(newCaseReviewerSET);
emptyCH.CaseReviewerSet = newCaseReviewerSET;
}
db.SaveChanges();
}
tran.Complete();
}
return response;
}
The exception occures on "db.SaveChanges()"
I saw in another post with the same error message something about "it seems I cannot have two connections opened to the same database with the TransactionScope block." but I dont think that this has anything to do with my case.
Additionally the number of records to insert and update in total are 2700, witch is not that many really. But it does take quite a lot of time to complete the for statement (10 minutes or so). Since everything happening within the for statement is actually happening in the memory can someone please explane why is this taking so long ?
You can try as shown below using latest db.Database.BeginTransaction API.
Note : use foreach instead of for
using (var db = new Entities.WaveEntities())
{
using (var dbContextTransaction = db.Database.BeginTransaction())
{
try
{
var maxCaseReviewersSetID = db.CaseReviewerSets.Select(crs => crs.CaseReviewersSetId).Max();
var emptyCHList = db.CaseHistories.Where(ch => ch.CaseReviewersSetID == null && ch.IsLatest == true && ch.StatusID != 100).ToList();
foreach(var ch in emptyCHList) {
var newCaseReviewerSET = new Entities.CaseReviewerSet();
newCaseReviewerSET.CreationCHID = ch.CHID;
db.CaseReviewerSets.Add(newCaseReviewerSET);
}
db.SaveChanges();
dbContextTransaction.Commit();
}
catch (Exception)
{
dbContextTransaction.Rollback();
}
}
}

How to change redis DB that the redis client is from redis pool

How can I changedb(redis command select), when I used the pool of redis.
I want write host and read host from different DB.
for example:
just now I only have one redis server,so the readWriteHosts = readOnlyHosts
pool = RedisDao.CreateManager(hostIp, hostIp);
public static PooledRedisClientManager CreateManager(string[] readWriteHosts, string[] readOnlyHosts)
{
return new PooledRedisClientManager(readWriteHosts, readOnlyHosts, new RedisClientManagerConfig
{
MaxWritePoolSize = 50,//
MaxReadPoolSize = 5,//
AutoStart = true,
});
}
public RedisDB ReadRedisForModel(String ID)
{
//here I want to use DB number is day%15
using (var redis = pool.GetClient())
{
RedisDB model = new RedisDB();
Dictionary<string, string> dic = redis.GetAllEntriesFromHash(keyPrefix + ID);
model.ID = ID;//Int32.Parse(ids[i]);
return model;
}
}
public void WriteRedis(RedisDB model)
{
//here I want to use DB number is (day-1)%15
using (var redis = pool.GetClient())
{
EDIT:
I find a way to set different DB,But I feel this solution is not best way.
if(redis is RedisClient)
{
long db = redis.DB;//db always = 0;
((RedisClient)redis).ChangeDB((day-1)%15);
}
Is it need to lock thread? when i am read or write to redis.
I am afraid, I got the same redis client in mutil-thread . then the redis DB is ?
Edit end
int time = DateTimeUtil.ConvertDateTimeInt(DateTime.Now);
model.ID = time + redis.Increment(incrementKey, 1) + "";//.Incr("ID");
using (var pip = redis.CreatePipeline())
{
pip.QueueCommand(r => r.AddItemToList(primaryKey, model.ID + ""));
pip.Flush();
};
};
}
I got redisClient from pool, but redisClient is not have the function of changeDB.
So anybody kowns how to set it?
for example:
//write
bool IsNeedChangeDB=true;
int WriteDBNumber=3
public static PooledRedisClientManager pool = RedisDao.CreateManager(hostIp, hostIp);
using (var redis = pool.GetClient())
{
if (redis is RedisClient && IsNeedChangeDB)
{
if (redis.Db != this.WriteDBNumber)
{
((RedisClient)redis).ChangeDb(this.WriteDBNumber);
}
else
{
Trace.WriteLine("it is a test" + redis.Host);
}
}
redis.Set<string>("key","value");
}
int ReadDBNumber=3;
//read
protected IRedisClient GetRedisClient()
{
var redis = pool.GetClient();
if (redis is RedisClient && IsNeedChangeDB)
{
if (redis.Db != this.ReadDBNumber)
((RedisClient)redis).ChangeDb(this.ReadDBNumber);
}
return redis;
}

Categories