MVC 6 How can I include a BaseRepository in my controller class - asp.net-mvc

I am using an ORM to connect to the database it is called dapper. The issue with it is that it's database calls are synchronous and I recently found a way to make it asynchronous by following this short tutorial http://www.joesauve.com/async-dapper-and-async-sql-connection-management/ . My question is how can I bring this BaseRepository into my Controller class ? This is the code on that website and it's the same one I have
BaseRepository- by the way there is no issue in this code
public abstract class BaseRepository
{
private readonly string _ConnectionString;
protected BaseRepository(string connectionString)
{
_ConnectionString = connectionString;
}
protected async Task<T> WithConnection<T>(Func<IDbConnection, Task<T>> getData)
{
try {
using (var connection = new SqlConnection(_ConnectionString)) {
await connection.OpenAsync(); // Asynchronously open a connection to the database
return await getData(connection); // Asynchronously execute getData, which has been passed in as a Func<IDBConnection, Task<T>>
}
}
catch (TimeoutException ex) {
throw new Exception(String.Format("{0}.WithConnection() experienced a SQL timeout", GetType().FullName), ex);
}
catch (SqlException ex) {
throw new Exception(String.Format("{0}.WithConnection() experienced a SQL exception (not a timeout)", GetType().FullName), ex);
}
}
}
and now he brings it in like this
public class PersonRepository : BaseRepository
{
public PersonRepository(string connectionString): base (connectionString) { }
public async Task<Person> GetPersonById(Guid Id)
{
return await WithConnection(async c => {
// Here's all the same data access code,
// albeit now it's async, and nicely wrapped
// in this handy WithConnection() call.
var p = new DynamicParameters();
p.Add("Id", Id, DbType.Guid);
var people = await c.QueryAsync<Person>(
sql: "sp_Person_GetById",
param: p,
commandType: CommandType.StoredProcedure);
return people.FirstOrDefault();
});
}
}
The part I am having a problem with is this public class PersonRepository : BaseRepository because Asp.Net Controllers start with public class HomeController: Controller , I need access to the WithConnection method to get this working. My controller looks like this
public class HomeController : Controller
{
public class ConnectionRepository : BaseRepository
{
public ConnectionRepository(string connectionString) : base(connectionString) { }
}
public async Task<ActionResult> topfive()
{
// I get Error on WithConnection as it can't see the BaseRepository
return await WithConnection(async c =>
{
var topfive = await c.QueryAsync<Streams>("select * from streams ").ToList();
return View(topfive);
});
}
}
I obviously can not cover my ActionResult method with the BaseRepository because it gives all types of errors any suggestions ?

Why are you using inheritance instead of composition? What about something like:
public class PersonRepository : BaseRepository
{
public PersonRepository(string connectionString): base (connectionString) { }
public async Task<Person> GetPersonById(Guid Id)
{
return await WithConnection(async c => {
// Here's all the same data access code,
// albeit now it's async, and nicely wrapped
// in this handy WithConnection() call.
var p = new DynamicParameters();
p.Add("Id", Id, DbType.Guid);
var people = await c.QueryAsync<Person>(
sql: "sp_Person_GetById",
param: p,
commandType: CommandType.StoredProcedure);
return people.FirstOrDefault();
});
}
}
public class ConnectionRepository : BaseRepository
{
public ConnectionRepository(string connectionString) : base(connectionString) { }
}
public async Task<List<TopFileClass>> topfive()
{
// I get Error on WithConnection as it can't see the BaseRepository
return await WithConnection(async c =>
{
var topfive = await c.QueryAsync<Streams>("select * from streams ").ToList();
return topfive;
});
}
public class HomeController : Controller
{
private readonly PersonRepository _repo;
public HomeController(PersonRepository repo)
{
_repo = repo;
}
public async Task<ActionResult> TopFive()
{
var top5 = await _repo.topfive();
return View(top5);
}
}
If you are not familiar how to make the repository automatically get injected into the constructor, read up on dependency injection in MVC 6.

you have to intehirt the "BaseRepository" from "Controller". i think that will work for you. then just go with below code:
public abstract class BaseRepository : Controller
{
// do you work
}
public class PersonRepository : BaseRepository
{
public PersonRepository(string connectionString): base (connectionString) { }
public async Task<Person> GetPersonById(Guid Id)
{
return await WithConnection(async c => {
// Here's all the same data access code,
// albeit now it's async, and nicely wrapped
// in this handy WithConnection() call.
var p = new DynamicParameters();
p.Add("Id", Id, DbType.Guid);
var people = await c.QueryAsync<Person>(
sql: "sp_Person_GetById",
param: p,
commandType: CommandType.StoredProcedure);
return people.FirstOrDefault();
});
}
}

Related

does razor page have onLoad method?

I know there is get and post method in razor page but what if you want you load some code soon as page is loads up? do I use a constructor method?
public async Task<IActionResult> OnGetAsync()
{
return Page();
}
public async Task<IActionResult> OnPostAsync(){
return Page();
}
Do you mean you want to use depedency injection?If so,you can try to use a constructor method.Firstly,you need to register a service in Program.cs,and then use a constructor in your pagemodel.
ICommentService:
public interface ICommentService
{
string Test();
}
CommentService:
public class CommentService : ICommentService
{
public string Test()
{
return "Test";
}
}
pageModel:
public class TestdModel : PageModel
{
private readonly ICommentService _commentService;
public TestdModel (ICommentService commentService)
{
_commentService = commentService;
}
}
Then you can use _commentService in your pagemodel.

Testing a Mvc controller that gets data from an API endpoint

I am working on a Web project that gets data from an API endpoint. The API layer sits on top of Service Layer and Repository Layer at the bottom. I have written unit testing for the Service and API Layers. I am using Moq framework to mock dependencies.
Now i want to test the MVC controller. I am using a Request Manager class which is derived from HttpClient to get data from the API endpoints. So how do i test this controller. I have written a unit test but the test is getting data directly from my Database.
public class UserController : Controller
{
private RequestManager requestManager = new RequestManager();
// GET: User
public async Task<ActionResult> Index()
{
List<UserViewModel> allUsers = await requestManager.GetUsers();
if(allUsers == null)
{
throw new HttpException(404, "No Users Found");
}
return View(allUsers);
}
}
public class UserControllerTest
{
public UserController controller;
[OneTimeSetUp]
public void InIt()
{
controller = new UserController();
}
[Test]
public async Task TestIndex()
{
var view = await controller.Index() as ActionResult;
Assert.That(view is ViewResult);
Assert.That(view.Model is List<UserViewModel>);
}
}
You should decouple controller and manager. Extract interface from RequestManager and inject it into controller. That should not be a problem, Ioc container can do that for you.
public class UserController : Controller
{
private RequestManager _requestManager;
public UserController(IRequestManager requestManager)
{
_requestManager = requestManager;
}
// GET: User
public async Task<ActionResult> Index()
{
List<UserViewModel> allUsers = await _requestManager.GetUsers();
if(allUsers == null)
{
throw new HttpException(404, "No Users Found");
}
return View(allUsers);
}
}
Then in your unit tests you can mock IRequestManager.
public class UserControllerTest
{
[Test]
public async Task TestIndex()
{
//arrange
Mock<IRequestManager> requestManager = new Mock<IRequestManager>();
//setup what you want here...
UserController sut = new UserController(requestManager.Object);//suggest to use AutoMoqer for this.
//act
var view = await sut.Index() as ActionResult;
//assert
Assert.That(view is ViewResult);
Assert.That(view.Model is List<UserViewModel>);
}
}
Try this one..
public class UserController : Controller
{
private RequestManager requestManager = new RequestManager();
Mock<RequestManager> mockRepository = new Mock<RequestManager>();
Mock<UserViewModel> mockUserViewModel = new Mock<UserViewModel>();
ViewResult viewResult;
// GET: User
public async Task<ActionResult> Index()
{
List<UserViewModel> allUsers = await requestManager.GetUsers();
if(allUsers == null)
{
throw new HttpException(404, "No Users Found");
}
return View(allUsers);
}
}
public class UserControllerTest
{
public UserController controller;
[OneTimeSetUp]
public void InIt()
{
controller = new UserController();
}
[Test]
public async Task TestIndexWhenAllUsersNULL()
{
var view = await controller.Index() as ActionResult;
List<mockUserViewModel> listofusermodel = new List<mockUserViewModel>();
//add some dummy data in your List so it will not getting data directly from your Database
mockRepository.Setup(x => requestManager.GetUsers()).Returns(listofusermodel);
Assert.That(view is ViewResult);
Assert.That(view.Model is List<mockUserViewModel>);
}
}

Get recent inserted Id and send in to another controllers view

EDITED:
I have Created CRUD Functions for each Modals and now i am trying to get recent Inserted Id and use it in different view.
Here is what I have tried so far
I have created 2 classes(Layer based) for CRUD function for each ContextEntities db to practice pure OOP recursive approach and following is the code.
1. Access Layer
ViolatorDB
public class ViolatorDB
{
private TPCAEntities db;
public ViolatorDB()
{
db = new TPCAEntities();
}
public IEnumerable<tbl_Violator> GetALL()
{
return db.tbl_Violator.ToList();
}
public tbl_Violator GetByID(int id)
{
return db.tbl_Violator.Find(id);
}
public void Insert(tbl_Violator Violator)
{
db.tbl_Violator.Add(Violator);
Save();
}
public void Delete(int id)
{
tbl_Violator Violator = db.tbl_Violator.Find(id);
db.tbl_Violator.Remove(Violator);
Save();
}
public void Update(tbl_Violator Violator)
{
db.Entry(Violator).State = EntityState.Modified;
Save();
}
public void Save()
{
db.SaveChanges();
}
}
2. Logic Layer
ViolatorBs
public class ViolatorBs
{
private ViolatorDB objDb;
public ViolatorBs()
{
objDb = new ViolatorDB();
}
public IEnumerable<tbl_Violator> GetALL()
{
return objDb.GetALL();
}
public tbl_Violator GetByID(int id)
{
return objDb.GetByID(id);
}
public void Insert(tbl_Violator Violator)
{
objDb.Insert(Violator);
}
public void Delete(int id)
{
objDb.Delete(id);
}
public void Update(tbl_Violator Vioaltor)
{
objDb.Update(Vioaltor);
}
}
And Finally using Logic Layer functions in presentation Layer.Here insertion is performed as:
public class CreateViolatorController : Controller
{
public TPCAEntities db = new TPCAEntities();
private ViolatorBs objBs;
public CreateViolatorController()
{
objBs = new ViolatorBs();
}
public ActionResult Index()
{
var voilator = new tbl_Violator();
voilator=db.tbl_Violator.Add(voilator);
ViewBag.id = voilator.VID;
return View();
}
[HttpPost]
public ActionResult Create(tbl_Violator Violator)
{
try
{
if (ModelState.IsValid)
{
objBs.Insert(Violator);
TempData["Msg"] = "Violator Created successfully";
return RedirectToAction("Index");
}
else
{
return View("Index");
}
}
catch (Exception ex)
{
TempData["Msg"] = "Failed..." + ex.Message + " " + ex.ToString();
return RedirectToAction("Index");
}
}
}
Now here is the main part how do i get perticuller inserted id in another controller named Dues while performing insertion ?
In sqlqery I would have used ##IDENTITY but in Entity Framework I'm not sure.
I'm new to mvc framework any suggestion or help is appreciated Thanks in Advance.
Once you save your db context the id is populated back to your entity by EF automatically.
for example.
using(var context = new DbContext())
{
var employee = new Employee(); //this has an id property
context.Employees.Add(employee);
context.SaveChanges();
var id = employee.id; // you will find the id here populated by EF
}
You dont need to add and save your table as you have done this already in your voilatorDB class just fetch the last id like following
var id = yourTableName.Id;
db.yourTableName.find(id);
Or you can simply write one line code to achive that using VoilatorBs class function
GetbyID(id);

MVC Get/Impersonate Windows User In Repository

I have an intranet application that uses the Windows username and passes that to a procedure to return data.
I'm using dependency injection, but I don't believe I have the method to get the username separated properly.
I'm trying to keep this secure by not passing in the username as a parameter, but I also want to be able to impersonate (or bypass my GetWindowsUser() method) and send in another username so I can test results for other users.
One idea I had for this was to set a session variable in another page with another (impersonated) username, then check if that session variable exists first before grabbing the actual user name, but I couldn't figure out how to access the session variable in the repository.
WEB API CONTROLLER
public class DropDownDataController : ApiController
{
private IDropDownDataRepository _dropDownDataRepository;
//Dependency Injection using Unity.WebAPI NuGet Package
public DropDownDataController(IDropDownDataRepository dropDownDataRepository)
{
_dropDownDataRepository = dropDownDataRepository;
}
[HttpGet]
public HttpResponseMessage MyList()
{
try
{
return _dropDownDataRepository.MyList();
}
catch
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
}
}
REPOSITORY
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
private DatabaseEntities db = new DatabaseEntities();
public HttpResponseMessage MyList()
{
//(This should be separated somehow, right?)
//Create a new instance of the Utility class
Utility utility = new Utility();
//Grab the windowsUser from the method
var windowsUser = utility.GetWindowsUser();
//Pass windowsUser parameter to the procedure
var sourceQuery = (from p in db.myProcedure(windowsUser)
select p).ToList();
string result = JsonConvert.SerializeObject(sourceQuery);
var response = new HttpResponseMessage();
response.Content = new StringContent(result, System.Text.Encoding.Unicode, "application/json");
return response;
}
}
INTERFACE
public interface IDropDownDataRepository : IDisposable
{
HttpResponseMessage MyList();
}
UTILITY CLASS
public class Utility
{
public string GetWindowsUser()
{
//Get the current windows user
string windowsUser = HttpContext.Current.User.Identity.Name;
return windowsUser;
}
}
UPDATE 1
In addition to what Nikolai and Brendt posted below, the following is also needed to allow Web Api controllers work with the session state.
Accessing Session Using ASP.NET Web API
Abstract the Utility class and inject it into the repository.
Then you can stub or mock for testing.
public interface IUtility
{
string GetWindowsUser();
}
public class TestUtility : IUtility
{
public string GetWindowsUser()
{
return "TestUser";
}
}
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
private IUtility _utility;
public DropDownDataRepository(IUtility utility)
{
_utility = utility;
}
}
EDIT
Also the repository should not return an HTTPResponseMessage type it should just return a List<T> of the domain model you're accessing.
i.e.
public List<Model> MyList()
{
//Grab the windowsUser from the method
var windowsUser = _utility.GetWindowsUser();
//Pass windowsUser parameter to the procedure
var sourceQuery = (from p in db.myProcedure(windowsUser)
select p).ToList();
return sourceQuery
}
Then move the JSON portion to the controller.
One idea I had for this was to set a session variable in another page
with another (impersonated) username, then check if that session
variable exists first before grabbing the actual user name, but I
couldn't figure out how to access the session variable in the
repository.
Potentially, if you add in a dependency to session, you need to isolate it, e.g.
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
// ... other fields
private ISession session;
public DropDownDataRepository(ISession session)
{
this.session = session;
}
public HttpResponseMessage MyList()
{
var myUserName = this.session.UserName;
// ... etc
With ISession being something like:
public interface ISession
{
string UserName { get; }
}
Implemented as:
public class MySession : ISession
{
public string UserName
{
get
{
// potentially do some validation and return a sensible default if not present in session
return HttpContext.Current.Session["UserName"].ToString();
}
}
}
Of course there is the potential to decouple this MySession class from HttpContext if desired.
With regards to this:
//(This should be separated somehow, right?)
//Create a new instance of the Utility class
Utility utility = new Utility();
Yes, anytime you create a new object you are tightly coupling them together, which will give you issues, for example, if you try to unit test it in isolation.
In this instance you could extract an IUtility interface from Utility:
public class Utility : IUtility
{
string GetWindowsUser();
}
Then:
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
// ... other fields
private IUtility utility;
public DropDownDataRepository(IUtility utility)
{
this.utility = utility;
// .... etc
Then you have removed the depenedency between Utility and DropDownDataRepository, and can substitute in another type or mock with ease.
I got a lot of help from Nikolai and Brent and got most of the way there with their posted answers, but ended up figuring out the complete answer on my own. The problems I was having were related to not being able to access session variables in a WebAPI. So, I'm sure there are cleaner solutions to this, but I definitely improved what I had and came up with the following code, which works.
This answer was needed to allow access to the session variable in Web Api - Accessing Session Using ASP.NET Web API
GLOBAL.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
UnityConfig.RegisterComponents();
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
//Added to allow use of session state in Web API
protected void Application_PostAuthorizeRequest()
{
if (IsWebApiRequest())
{
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}
}
//Added to allow use of session state in Web API
private bool IsWebApiRequest()
{
return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith(WebApiConfig.UrlPrefixRelative);
}
protected void Session_Start(Object sender, EventArgs e)
{
//Default set the session variable to none
Session["_impersonatedUser"] = "none";
}
protected void Session_End(Object sender, EventArgs e)
{
//Reset the session variable to blank
Session["_impersonatedUser"] = "";
}
}
UNITY.config
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
container.RegisterType<IDropDownDataRepository, DropDownDataRepository>();
container.RegisterType<IUtilityRepository, UtilityRepository>();
container.RegisterType<ISessionRepository, SessionRepository>();
//MVC5
//Unity.MVC5 NuGet Package
DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));
//WEB API
//Unity.WebApi NuGet Package
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
}
WEB API CONTROLLER
public class DropDownDataController : ApiController
{
private IDropDownDataRepository _dropDownDataRepository;
//Dependency Injection using Unity.WebAPI NuGet Package
public DropDownDataController(IDropDownDataRepository dropDownDataRepository)
{
_dropDownDataRepository = dropDownDataRepository;
}
[HttpGet]
public HttpResponseMessage MyList()
{
try
{
var sourceQuery = _dropDownDataRepository.MyList();
//JSON stuff moved to controller
string result = JsonConvert.SerializeObject(sourceQuery);
var response = new HttpResponseMessage();
response.Content = new StringContent(result, System.Text.Encoding.Unicode, "application/json");
return response;
}
catch
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
}
protected override void Dispose(bool disposing)
{
_dropDownDataRepository.Dispose();
base.Dispose(disposing);
}
}
DROPDOWNDATA REPOSITORY
public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
private DatabaseEntities db = new DatabaseEntities();
private IUtilityRepository _utilityRepository;
private ISessionRepository _sessionRepository;
//Dependency Injection of Utility and Session
public DropDownDataRepository(IUtilityRepository utilityRepository, ISessionRepository sessionRepository)
{
_utilityRepository = utilityRepository;
_sessionRepository = sessionRepository;
}
//Changed to a list here
public List<MyProcedure> MyList()
{
string windowsUser;
//Check the session variable to see if a user is being impersonated
string impersonatedUser = _sessionRepository.ImpersonatedUser;
//Grab the windowsUser from the Utility Repository
windowsUser = _utilityRepository.GetWindowsUser();
if (impersonatedUser != "none")
{
windowsUser = impersonatedUser;
}
//Pass windowsUser parameter to the procedure
var sourceQuery = (from p in db.MyProcedure(windowsUser)
select p).ToList();
return sourceQuery;
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
db.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
DROPDOWNDATA INTERFACE
public interface IDropDownDataRepository : IDisposable
{
//Changed to list here
List<MyProcedure> MyList();
}
UTILITY REPOSITORY
public class UtilityRepository : IUtilityRepository
{
public string GetWindowsUser()
{
//Get the current windows user
string windowsUser = HttpContext.Current.User.Identity.Name;
return windowsUser;
}
}
UTILITY INTERFACE
public interface IUtilityRepository
{
string GetWindowsUser();
}
SESSION REPOSITORY
public class SessionRepository : ISessionRepository
{
public string ImpersonatedUser
{
get
{
return HttpContext.Current.Session["_impersonatedUser"].ToString();
}
}
}
SESSION INTERFACE
public interface ISessionRepository
{
string ImpersonatedUser { get; }
}

IMobileServiceClient.PullAsync deadlock when trying to sync with Azure Mobile Services

I have the classes below.
public class AzureMobileDataContext : IAsyncInitialization
{
private static readonly Lazy<AzureMobileDataContext> lazy =
new Lazy<AzureMobileDataContext> (() =>
new AzureMobileDataContext(
new MobileServiceClient(
"http://myservice.azure-mobile.net/",
"123456789ABCDEFGHIJKLMNOP")));
public static AzureMobileDataContext Instance { get { return lazy.Value; } }
public Task Initialization { get; private set; }
public IMobileServiceClient Context { get; private set; }
private Object lockObj = new Object ();
private static MobileServiceSQLiteStore store;
public AzureMobileDataContext (IMobileServiceClient context)
{
Context = context;
Initialization = Init ();
Initialization.ContinueWith (async (antecedent) => {
await Context.SyncContext.InitializeAsync (store, new MobileServiceSyncHandler ());
});
}
private Task Init ()
{
return Task.Run (() => {
lock (lockObj) {
if (!Context.SyncContext.IsInitialized) {
try {
store = new MobileServiceSQLiteStore ("mysqlite.db3");
store.DefineTable<Post> ();
store.DefineTable<PostPhotoUrl> ();
store.DefineTable<User> ();
store.DefineTable<Club> ();
store.DefineTable<District> ();
} catch (Exception ex) {
Debug.WriteLine ("Init: {0}", ex.Message);
}
}
}
});
}
public async Task<IMobileServiceSyncTable<TEntity>> GetTableAsync<TEntity> ()
{
await Initialization;
return Context.GetSyncTable<TEntity> ();
}
public async Task PushAsync ()
{
try {
await Initialization;
await Context.SyncContext.PushAsync ();
} catch (MobileServiceInvalidOperationException invalidOperationEx) {
Debug.WriteLine (invalidOperationEx.Message);
} catch (MobileServicePushFailedException pushFailedException) {
Debug.WriteLine (pushFailedException.Message);
}
}
public async Task PullAsync<TEntity> (IMobileServiceTableQuery<TEntity> query)
{
try {
await Initialization;
IMobileServiceSyncTable<TEntity> entityTable = await GetTableAsync<TEntity> ();
await entityTable.PullAsync (typeof(TEntity).ToString (), query); // Never returns, no exception is caught or thrown.
await entityTable.PurgeAsync ();
} catch (MobileServiceInvalidOperationException preconditionFailedEx) {
Debug.WriteLine (preconditionFailedEx.Message);
} catch (Exception ex) {
Debug.WriteLine (ex.Message);
}
}
public async Task SyncAsync<TEntity> ()
{
await PushAsync ();
IMobileServiceSyncTable<TEntity> syncTable = await GetTableAsync<TEntity> ();
await PullAsync (syncTable.CreateQuery ());
}
}
I use this singleton from a BaseRepository I have that is a base class for 5 different entity repositories.
public abstract class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected AzureMobileDataContext MobileServiceContext { get { return AzureMobileDataContext.Instance; } }
protected virtual Task PushAsync ()
{
return MobileServiceContext.PushAsync ();
}
protected virtual Task PullAsync (IMobileServiceTableQuery<TEntity> query)
{
return MobileServiceContext.PullAsync (query);
}
public virtual async Task<DataObjectResponse<IEnumerable<TEntity>>> FindAsync (Expression<Func<TEntity, bool>> predicate)
{
IMobileServiceSyncTable<TEntity> syncTable = await MobileServiceContext.GetTableAsync<TEntity> ();
await PullAsync (syncTable.CreateQuery ());
IEnumerable<TEntity> entities = await syncTable.Where (predicate).ToEnumerableAsync ();
return new DataObjectResponse<IEnumerable<TEntity>> (entities);
}
}
The users repository.
public class UsersAzureRepository : BaseRepository<User>, IUsersRepository
{
public UsersAzureRepository ()
{
}
public async Task<DataObjectResponse<User>> FindByIdAsync (string entityId)
{
DataObjectResponse<IEnumerable<User>> users = await FindAsync (p => p.Id == entityId);
return new DataObjectResponse<User>(users.Data.FirstOrDefault ());
}
}
A DataService Facade class containing the GetUserById method.
public async Task<UserModel> GetUserById (string userId)
{
DataObjectResponse<User> users = await UsersRepository.FindByIdAsync (userId);
UserModel userModel = Mapper.Map<User, UserModel> (users.Data);
return userModel;
}
Users view model method.
public async Task<UserModel> GetUsersAsync() // testing purposes
{
UserModel user = await _dataService.GetUserById("032beb3b-1cbf-4a0d-809c-a25c71139c55");
if (user != null) {
Debug.WriteLine ("User loaded: {0}", user.Id);
}
return user;
}
Call from an iOS UIViewController.
public async override void ViewDidLoad ()
{
base.ViewDidLoad ();
UserModel user = await ViewModel.GetUsersAsync ();
}
The AzureMobileDataContext serves more as a thread safe wrapper to the IMobileServiceClient context operations, making sure not multiple threads will try to initialize the database (I had an exception when using it directly to the BaseRepository<T> before).
I'm not so sure from here where might the problem is. I suspect that the wrapper is not the best solution and any recommendations are welcome.
Any other ways to debug the PullAsync method?
[EDIT]
The local SQLite database syncs the table data from the remote service but still the call doesn't return.
The problem was in the Azure Mobile Service, server side.
I was returning from the TableController an IEnumerable but the SDK uses OData query expressions to do it's own job, returning an IEnumerable is not sufficient, changing to IQueryable fixed this issue of a continuous looping when pulling data.
I strongly believe that the server return type shouldn't be related to the SDK but this is the way it works.

Resources