I implementing a IMobileServiceSyncHandler. My goal is to implement a "server always wins mechanism". So when a conflict is detected the IMobileServiceSyncHandler should overwrite the local copy with the server copy.
Here is my code:
class MySyncHandler : IMobileServiceSyncHandler
{
public IMobileServiceSyncTable<Error> localTable;
IMobileServiceClient client;
public MySyncHandler(IMobileServiceClient client)
{
this.client = client;
}
public async Task<JObject> ExecuteTableOperationAsync(IMobileServiceTableOperation operation)
{
JObject result = null;
MobileServicePreconditionFailedException conflictError = null;
do
{
try
{
result = await operation.ExecuteAsync();
}
catch (MobileServicePreconditionFailedException e)
{
conflictError = e;
}
if (conflictError != null)
{
JObject serverItem = conflictError.Value;
if (serverItem == null)
{
serverItem = (JObject)(await operation.Table.LookupAsync((string)operation.Item[MobileServiceSystemColumns.Id]));
}
await localTable.UpdateAsync(serverItem);
}
} while (conflictError != null);
return result;
}
public Task OnPushCompleteAsync(MobileServicePushCompletionResult result)
{
return Task.FromResult(0);
}
}
The relevant part is:
await localTable.UpdateAsync(serverItem);
My idea is to update the local table with the server version.
My Problem:
This does not work. The local copy does not change. It remains on the local version.
Can you help?
The same engineer has a more complete example here: Azure Mobile Services - Handling Conflicts with Offline.
In order to keep the server version of the record, replace this line:
await localTable.UpdateAsync(serverItem);
with
return serverItem;
inside the if block for when there is a conflict.
Related
For a few months now I have been using the ktor framework to create servers that expose rest calls and communication via webSockets. For now I have always used clients using kotlin as a programming language (or Android App, or App Desktop).
Specifically, I had a class that was injected with the HttpClient object (from the documentation = Asynchronous client to perform HTTP requests).
Within this class I have 4 methods:
start the session: instantiate the WebSocketSession object (Represents a web socket session between two peers)
send Frame
receives Frame
close the session
In Ktor my class is something that looks a lot like this:
class WebSocketServiceImpl(
private val client: HttpClient
){
private var socket: WebSocketSession? = null
//1)
suspend fun initSession(username: String): Resource<Unit>{
socket = client.webSocketSession {
url("ws://xxx.xxx.xxx.xxx:xxxx/myRoute?username=$username")
}
//2)
suspend fun send(myObj: MyObj) {
try {
val myObjSerialized = Json.encodeToString(myObj)
socket?.send(Frame.Text(myObjSerialized ))
} catch (e: Exception) {
e.printStackTrace()
}
}
//3)
fun observePrintableMessages(): Flow<MyObj> {
return try {
socket?.incoming
?.receiveAsFlow()
?.filter { it is Frame.Text }
?.map {
val myObjString = (it as? Frame.Text)?.readText() ?: ""
val printableMessageDto = Json.decodeFromString<MyObj>(myObjString)
} ?: flow { }
} catch (e: Exception) {
e.printStackTrace()
flow { }
}
}
//4)
suspend fun closeSession() {
socket?.close()
}
}
From the C # documentation instead, I found these examples on how to use Client-side WebSockets:
//1)
const exampleSocket = new WebSocket("wss://www.example.com/socketserver", "protocolOne");
//2)
exampleSocket.send("Here's some text that the server is urgently awaiting!");
//3)
exampleSocket.onmessage = (event) => {
console.log(event.data);
}
//4)
exampleSocket.close();
Admitted and not granted that the methods I found in C # really work, to make the WebSocket object used in C # be equivalent to the WebSocketSession object in Kotlin is enough for me to do so? :
public void initSession(string username)
{
exampleSocket = new WebSocket($"wss://www.example.com/socketserver?username={username}", "");
}
Or is it some other type of object to use?
If for any reason you don't know the answer, you don't need to vote negative, you can just move on.
I used the Websocket.Client library (by Mariusz Kotas) found on NuGet
public class WebSocketService : IWebSocketService
{
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
private void FireMessageReceivedEvent(Message message) => MessageReceived?.Invoke(this, new MessageReceivedEventArgs(message));
public string Url { get => "ws://192.168.1.202:8082/chat-socket"; }
private WebsocketClient webSocketClient;
public async Task<SessionResoult> InitSession(string username)
{
string usernameSession = $"?username={username}";
string urlWithUsername = $"{Url}{usernameSession}";
try
{
webSocketClient = new WebsocketClient(new Uri(urlWithUsername));
await webSocketClient.Start();
if (webSocketClient.IsRunning)
{
SubscribeNewMessages();
return new SessionResoult.Success();
}
else
{
return new SessionResoult.Error("webSocketClient is not running");
}
}
catch(Exception ex)
{
return new SessionResoult.Error(ex.Message);
}
}
private void SubscribeNewMessages()
{
webSocketClient.MessageReceived.Subscribe(m =>
{
MessageDto message = JsonConvert.DeserializeObject<MessageDto>(m.Text);
FireMessageReceivedEvent(message.ToMessage());
});
}
public async Task SendMessageAsync(string message)
{
await Task.Run(() => webSocketClient.Send(message));
}
public void CloseSession()
{
webSocketClient.Dispose();
}
}
In the code, the interesting parts are:
1) initialization of the WebsocketClient object
2) the subscription of receiving messages ( Start() method immediately after initialization)
3) observation of message subscription -> webSocketClient.MessageReceived.Subscribe
4) the 'Fire' of the event linked to the observation of messages -> FireMessageReceivedEvent
5) those who use the class must subscribe to the event of the latter ->
webSocketService.MessageReceived + = (sender, e) => {OnMessageReceived (e.MessageReceived); };
MessageReceivedEventArgs -> Class describing the Arguments of the event
SessionResoult -> Class similar to an Enum but with the possibility of passing a string or not based on which subclass it is
i have table for set user Access Level in Tabel .
this is my Access :
public Guid RoleId { get; set ; }
public string Access { get ; set ; }
i want when the AccessLevel is changed it must changed the SecurityStamp in Role table .
public async Task<OperationResult<string>> Handle(SetAccessLevelCommand request, CancellationToken cancellationToken)
{
var result = await unitOfWork.RoleRepository.AccessLevelRepository.SetAccess(new AccessLevelDto { RoleId = request.RoleId, Access = request.AccessList });
if (result.Success)
{
try
{
try
{
var findRole = await unitOfWork.RoleRepository.GetRoleByIdAsync(request.RoleId, cancellationToken);
findRole.Result.UpdateSecurityStamp();
if (findRole.Result != null)
{
unitOfWork.RoleRepository.Update(findRole.Result, cancellationToken);
unitOfWork.CommitSaveChange();
return OperationResult<string>.BuildSuccessResult("Add Success");
}
}
catch (Exception ex)
{
return OperationResult<string>.BuildFailure(ex.Message);
}
}
catch (Exception ex)
{
return OperationResult<string>.BuildFailure(ex.Message);
}
}
return OperationResult<string>.BuildFailure(result.ErrorMessage);
}
i write this code for doing this work .
this is the SetAccess :
public async Task<OperationResult<string>> SetAccess(AccessLevelDto accessLevels)
{
try
{
var currentRoleAccessValue = GetAccessLevels(accessLevels.RoleId);
var currentAccess = currentRoleAccessValue.Select(x => x.Access).ToList();
var newAccess = accessLevels.Access.Except(currentAccess).ToList();
if (newAccess != null)
{
foreach (var item in newAccess)
{
context.Add(new AccessLevel
{
Access = item,
RoleId = accessLevels.RoleId
});
}
}
var removeItems = currentAccess.Except(accessLevels.Access).ToList();
if (removeItems != null)
{
foreach (var item in removeItems)
{
var accClaim = currentRoleAccessValue.SingleOrDefault(x => x.Access == item);
if (accClaim != null)
{
context.Remove(accClaim);
}
}
}
return OperationResult<string>.BuildSuccessResult("SuccessAdd");
}
catch (Exception ex)
{
return OperationResult<string>.BuildFailure(ex);
}
}
this is code for change State of entity and it's worked fine and when i call the CommitSaveChange() it worked fine . but when i add the RoleUpdate commands :
var findRole = await unitOfWork.RoleRepository.GetRoleByIdAsync(request.RoleId, cancellationToken);
findRole.Result.UpdateSecurityStamp();
if (findRole.Result != null)
{
unitOfWork.RoleRepository.Update(findRole.Result, cancellationToken);
}
and then call the unitOfWork.CommitSaveChange() it show me this error :
Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances. Object name: 'FilmstanContext'.
whats the problem ? how can i solve this problem ????
When I have seen this type of issue in the past, it has usually been due to either a) missing await commands or b) async methods with a void return type. In my case, it was related to Entity Framework. Just in case it helps. Cannot access a disposed object
A related observation, I would think your call to CommitSaveChange should be asynchronous. This probably writes data to some type of data store. If reading 'GetRoleById' is async, I would think writing should also be async. Just my 2 cents.
I´m currently developing an iOS App with Xamarin and ran into a strange error with sqlite-net-pcl:
{SQLite.SQLiteException: near ")": syntax error at SQLite.SQLite3.Prepare2 (SQLitePCL.sqlite3 db, System.String query) [0x0001e] in <49ac49cfb94341128f6929b3ff2090ee>:0 at SQLite.PreparedSqlLiteInsertCommand.Prepare () [0x00011] in <49ac49cfb94341128f6929b…}
The error occours when I want to insert into a table of the following model:
public class PPPCount
{
public PPPCount()
{
}
[PrimaryKey]
public int Id { get; set; }
public string PerpePartCount { get; set; }
}
Here is the calling code:
try
{
var con = await DbFactory.Instance();
var perpetrationPartCount = await
service.GetSumPerpetrationParts(immobilePerpetrationId);
var dbModel = await con.FindAsync<PPPCount>(immobilePerpetrationId);
if (dbModel == null)
{
var model = new PPPCount();
model.Id = immobilePerpetrationId;
model.PerpePartCount = perpetrationPartCount;
//This causes the exception!!!!
await con.InsertAsync(perpetrationPartCount);
}
else
{
if (dbModel.PerpePartCount != perpetrationPartCount)
{
dbModel.PerpePartCount = perpetrationPartCount;
await con.UpdateAsync(dbModel);
}
}
return perpetrationPartCount;
}
catch (Exception e)
{
//AlertHelper.ShowError(e.Message);
}
The code of the DbFactory that creates and holds my sqlite connection object:
public class DbFactory
{
private static SQLiteAsyncConnection connection;
public static async Task<SQLiteAsyncConnection> Instance()
{
if (connection == null)
{
bool deleteDb = false;
string folder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
var dbPath = System.IO.Path.Combine(folder, "..", "immotech_offline.db3");
if (File.Exists(dbPath) && deleteDb)
{
File.Delete(dbPath);
}
connection = new SQLiteAsyncConnection(dbPath);
try
{
await connection.CreateTableAsync<ImmobilePerpetration>();
await connection.CreateTableAsync<Customer>();
await connection.CreateTableAsync<PPPCount>();
}
catch (Exception e)
{
//TODO: Delete this part!
int i = 0;
}
}
return connection;
}
}
The strange thing is I can work with the two other models without any problems!
I really can´t explain what is causing this error and I tried to enable the tracing to show the SQL-Statements, but unfortunatelly the Async version of the sqlite connection object doesn´t provide a tracing.
Then I tried the same code in synchronous version with tracing enabled and this is the result:
insert into "Int32"() values ()
Well this is very clear why it isn´t working, but how can such a statement be generated? Did I missed something or it is a bug?
UPDATE: Yes I used the search function and no case fits for my problem.
Should this:
await con.InsertAsync(perpetrationPartCount);
be:
await con.InsertAsync(model);
We can't tell what type perpetrationPartCount is based on your code. It might not be a PPPCount and therefore that entity might not be the issue.
I have a Windows Phone 8.1 Class Library that I want to later add as a reference to a Windows Phone 8.1 App project.
This ClassLibrary should be responsible for creating and managing its own database. I tried creating a new SQLiteConnection in my ClassLibrary, but it throws the following error: A first chance exception of type 'System.InvalidOperationException' occurred in SQLitePCL.DLL however, if I do the same in my MainApp everything works fine.
So, is it possible to create a SQLite database in a ClassLibrary that's responsible for creating and managing it without any support from the MainApp.
I have a project in it where the SQLite library is in a class library and then I use another class library for the communication between my app and the SQLite library
Class library: SQLite.Library
Make a new class library (in my case I named it SQLite.Library)
Right click > Manage NuGet packages > sqlite-net (https://www.nuget.org/packages/sqlite-net/1.0.8)
After adding this NuGet package you see that your class library has 2 new classes: SQLite.cs and SQLiteAsync.cs.
Also there is a known problem with SQLite and threading (NullReferenceException when page Loads), you can fix it by adding a lock in the method TableMapping GetMapping in SQLite.cs:
public TableMapping GetMapping(Type type, CreateFlags createFlags = CreateFlags.None)
{
if (_mappings == null) {
_mappings = new Dictionary<string, TableMapping> ();
}
lock (_mappings)
{
TableMapping map;
if (!_mappings.TryGetValue(type.FullName, out map))
{
map = new TableMapping(type, createFlags);
_mappings[type.FullName] = map;
}
return map;
}
}
Class library: Solutionname.Lib
Make a new class library (in my case I named it Solutionname.Lib)
Right click > Add Reference > Solution > SQLite.Library (the class library u just made)
After the reference is set u can use the SQLite library in this class library.
In my project I tried to split my code a bit so I started with making a class named DatabaseHelper.cs:
public class DatabaseHelper
{
private String DB_NAME = "DATABASENAME.db";
public SQLiteAsyncConnection Conn { get; set; }
public DatabaseHelper()
{
Conn = new SQLiteAsyncConnection(DB_NAME);
this.InitDb();
}
public async void InitDb()
{
// Create Db if not exist
bool dbExist = await CheckDbAsync();
if (!dbExist)
{
await CreateDatabaseAsync();
}
}
public async Task<bool> CheckDbAsync()
{
bool dbExist = true;
try
{
StorageFile sf = await ApplicationData.Current.LocalFolder.GetFileAsync(DB_NAME);
}
catch (Exception)
{
dbExist = false;
}
return dbExist;
}
private async Task CreateDatabaseAsync()
{
//add tables here
//example: await Conn.CreateTableAsync<DbComment>();
}
}
After the creation of the DatabaseHelper class u can start by making a datasource class for each table in your database.
In my case i have a CommentDataSource.cs:
public class CommentDataSource
{
private DatabaseHelper db;
public CommentDataSource(DatabaseHelper databaseHelper)
{
this.db = databaseHelper;
}
public async Task<long> AddComment(String vat, String comment)
{
long id = 0;
DateTime date = DateTime.Now;
DbComment dbc = new DbComment(vat, comment, date);
await db.Conn.InsertAsync(dbc);
DbComment insertDbc = await db.Conn.Table<DbComment>().ElementAtAsync(await db.Conn.Table<DbComment>().CountAsync() - 1);
if (insertDbc != null)
{
id = insertDbc.Id;
}
return id;
}
public async void RemoveComment(long idComment)
{
DbComment comment = await db.Conn.Table<DbComment>().Where(c => c.Id == idComment).FirstOrDefaultAsync();
if (comment != null)
{
await db.Conn.DeleteAsync(comment);
}
}
public async Task<List<DbComment>> FetchAllComments(String vat)
{
return await db.Conn.Table<DbComment>().Where(x => x.VAT == vat).ToListAsync();
}
}
As you can see all the datasources that u will add will make use of the same databasehelper.
Use the Solutionname.Lib in your app
Right click > Add Reference > Solution > SQLite.Library (the class library u just made)
Right click > Add Reference > Solution > Solutionname.Lib
You still need to add a reference to your sqlite lib otherwise you will get errors.
Now you can start using your datasource classes, like u can see here:
private DatabaseHelper db = new DatabaseHelper();
private CommentDataSource commentDataSource;
public MainPage()
{
this.InitializeComponent();
commentDataSource = new CommentDataSource(db);
}
Now is every method of the CommentsDataSource available in your app.
Hope this help u a bit!
try this
public async Task<bool> CheckDbAsync(string dbName)
{
bool dbExist = true;
try
{
StorageFile sf = await ApplicationData.Current.LocalFolder.GetFileAsync(dbName);
}
catch (Exception)
{
dbExist = false;
}
return dbExist;
}
public async Task CreateDatabaseAsync(string dbName)
{
SQLiteAsyncConnection con = new SQLiteAsyncConnection(dbName);
await con.CreateTableAsync<ChatClass>();
// await con.CreateTableAsync<RecentChatManageClass>();
await con.CreateTableAsync<PurchasedGift>();
// await con.CreateTableAsync<AttandanceManagement>();
}
and use like this
DataBaseOperation databaseoperation = new DataBaseOperation();
bool existDb = await databaseoperation.CheckDbAsync("sample.db"); // Check Database created or not
if (!existDb)
{
await databaseoperation.CreateDatabaseAsync("sample.db"); // Create Database
}
I'm having problem using wcf with wp8.1 silverlight. I countinously getting the error The contract 'IPhoneService' contains synchronous operations, which are not supported in Silverlight. Split the operations into "Begin" and "End" parts and set the AsyncPattern property on the OperationContractAttribute to 'true'. Note that you do not have to make the same change on the server. After I changed my syncronous method to async I'm still getting the same error (I updated the service reference.). Out of curiousity I tried to use it on a console app, and it works perfectly.
Previously I did get an another error that might have something to do with it. Adding a service reference generated an app.config file, but the app needed a ServiceReferences.ClientConfig, so I simply renamed it.
For now I changed back the WCF method to syncronous:
public int GetData()
{
return 12;
}
and on my MainViewModel (I'm using MVVMLight toolkit):
public void Load()
{
var client = new ServiceReference1.PhoneServiceClient();
client.GetDataCompleted += client_GetDataCompleted;
client.GetDataAsync();
}
void client_GetDataCompleted(object sender, ServiceReference1.GetDataCompletedEventArgs e)
{
Title = e.Result.ToString();
}
and i implemeneted before the async method like this, getting the same error anyway:
public IAsyncResult BeginGetData(AsyncCallback callback, object asyncState)
{
var msg = 12;
return new CompletedAsyncResult<int>(msg);
}
public int EndGetData(IAsyncResult r)
{
CompletedAsyncResult<int> result = r as CompletedAsyncResult<int>;
return result.Data;
}
class CompletedAsyncResult<T> : IAsyncResult
{
T data;
public CompletedAsyncResult(T data)
{ this.data = data; }
public T Data
{ get { return data; } }
#region IAsyncResult Members
public object AsyncState
{ get { return (object)data; } }
public WaitHandle AsyncWaitHandle
{ get { throw new Exception("The method or operation is not implemented."); } }
public bool CompletedSynchronously
{ get { return true; } }
public bool IsCompleted
{ get { return true; } }
#endregion
}
The problem was VS2013 RC2 version. The reference wasn't generated correctly. An update solved the problem