I have a weird error in Redis on .Net 6. When I run the test code here:
https://github.com/redis-developer/redis-graph-dotnet-basic-app/blob/main/Program.cs
It works perfectly fine. In this case the code is running in the program.cs file.
When I port that code to a class, in order to better manage encapsulation and complexity. It does not work. What it does is run the code and when it gets to the: await graph.QueryAsync part, it just stops the debugger. Very strange indeed.
Here is the code I am using. Any thoughts or suggestions:
//Program.cs (Relevant Bits)
using RedisTest //PROGRAM //WRITE TO REDIS ENTERPRISE CLOUD Process_LoadGraph process_LoadGraph = new Process_LoadGraph(); process_LoadGraph.Controller(results);
//SHARED CONNECTION CLASS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StackExchange.Redis;
namespace RedisTest
{
public class RedisSharedConnection
{
public static ConnectionMultiplexer Connection
{
get
{
return lazyConnection.Value;
}
}
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
ConnectionMultiplexer connectionMultiplexer = ConnectionMultiplexer.Connect(ConfigData.dbConnectionString);
return connectionMultiplexer;
});
}
}
//USAGE CLASS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NRedisGraph;
namespace RedisTest
{
public class Process_LoadGraph
{
public async void Controller(List<Result> results)
{
//Setup
var redisConnection = RedisSharedConnection.Connection;
//var redisConnection = ConnectionMultiplexer.Connect(ConfigData.dbConnectionString);
var db = redisConnection.GetDatabase(ConfigData.dbId);
var graph = new RedisGraph(db);
string graphName = ConfigData.graphName;
//Test Transaction
// Create Bob
// CRASHES HERE
var createBobResult = await graph.QueryAsync("pets", "MERGE(:human{name:'Bob',age:32})");
}
}
}
Turns out the solution is to use Redis in a static class. Along the following lines:
internal static class WriteToDB
{
public static async Task WriteAsync(List<string> querieS)
{
//Load Graph
//Setup
var redisConnection = RedisSharedConnection.Connection;
//var redisConnection = ConnectionMultiplexer.Connect(ConfigData.dbConnectionString);
var db = redisConnection.GetDatabase(ConfigData.dbId);
var graph = new RedisGraph(db);
string graphName = ConfigData.graphName;
// ** DEBUG
//Test Transaction
// Create Bob
var createBobResult = await graph.QueryAsync("pets", "MERGE(:human{name:'Bob',age:32})");
{ }
//Clear Graph
await graph.QueryAsync(graphName, "MATCH(n) DETACH DELETE n");
{ }
}
}
Related
I have an app that has two components. One is a C# console app that will run as a service in production. The other component is the UI which is a WPF app that runs as a system tray app. This article is what I used to get off the ground. Both apps target .NET6.
I need to send messages through the named pipe, which is implemented with the H.pipes nuget package, from both the console app and the WPF app. I am currently defining the named pipes object as a static variable in a static class so I can access it across multiple classes. Like so:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WindowsTapAgent
{
internal static class Globals
{
public static NamedPipesServer pipeServer;
}
}
The named pipe is initialized in the console app like this:
using Newtonsoft.Json;
using Serilog;
using WindowsTapAgent;
using System.Net.NetworkInformation;
using System.Reflection;
string logFileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\" + "DrawbridgeAgent.log";
Log.Logger = new LoggerConfiguration()
// add a rolling file for all logs
.WriteTo.File(logFileName,
fileSizeLimitBytes: 2000000)
.WriteTo.Console()
.WriteTo.EventLog("Drawbridge Agent Source", manageEventSource: true)
// set default minimum level
.MinimumLevel.Information()
.CreateLogger();
Globals.pipeServer = new NamedPipesServer();
Globals.pipeServer.InitializeAsync().GetAwaiter().GetResult();
...
...
...
...
The actual code that accesses the named pipe is as follows:
using Serilog;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using System.Net.Http.Headers;
using System.Text;
namespace WindowsTapAgent
{
public class TapDevice
{
public RsaKey RsaKey { get; set; }
//private NamedPipesServer PipeServer { get; set; }
public TapDevice(AgentConfigInfo info)
{
Log.Information("In TapDevice Constructor");
string containerName = info.RsaKeyContainerName;
Log.Information("ContainerName: " + containerName);
RsaKey = new RsaKey(containerName);
Log.Information("RSAKey Public Key: " + RsaKey.getPublicKeyData());
}
public async Task<AgentConfigInfo> Register(RegistrationToken regToken, AgentConfigInfo info)
{
try
{
Log.Information("-----------------------------Attempting to register------------------------------.");
if (Globals.pipeServer != null)
Globals.pipeServer.SendMessage("Registering with Drawbridge");
...
...
...
NamedPipeServer class:
using H.Pipes;
using H.Pipes.Args;
using Common;
namespace WindowsTapAgent
{
public class NamedPipesServer : IDisposable
{
const string PIPE_NAME = "drawbridgepipe";
private PipeServer<PipeMessage> server;
private PipeConnection<PipeMessage> connection;
public async Task InitializeAsync()
{
server = new PipeServer<PipeMessage>(PIPE_NAME);
server.ClientConnected += async (o, args) => await OnClientConnectedAsync(args);
server.ClientDisconnected += (o, args) => OnClientDisconnected(args);
server.MessageReceived += (sender, args) => OnMessageReceived(args.Message);
server.ExceptionOccurred += (o, args) => OnExceptionOccurred(args.Exception);
await server.StartAsync();
}
private async Task OnClientConnectedAsync(ConnectionEventArgs<PipeMessage> args)
{
//Console.WriteLine($"Client {args.Connection.Id} is now connected!");
connection = args.Connection;
}
...
...
...
The problem is that the TapDevice class is used in both the console app and the WPF app. When the PipeServer object is accessed through the TapDevice class from the console app (where it's also declared and initialized) everything works fine. When it's called from the WPF app, again through the TapDevice class, the PipeServer object is always null, and can't be used. How should I better structure this project?
I figured it out. I had the client and server mixed up. I needed to put the server on the UI side, then I can can create multiple client connections to it as needed. This eliminates the need for the messy global variable that didn't work anyways.
I'm fairly new to .NET and c# and I'm working on a POC where I've run into an issue when a controller throws the error
System.InvalidOperation Exception {"Unable to resolve controller: TenantController"}
The Inner exception details are
No default Instance is registered and cannot be automatically determined for type 'GICS.Web.Managers.Interfaces.ITenantManager'
There is no configuration specified for GICS.Web.Managers.Interfaces.ITenantManager
1.) new TenantController(Default of ITenantManager, Default of IRemedyService)
2.) GICS.Web.Controllers.Api.TenantController
3.) Instance of GICS.Web.Controllers.Api.TenantController
4.) Container.GetInstance(GICS.Web.Controllers.Api.TenantController)
The TenantController looks as follows:
using System.Web.Mvc;
using GICS.Web.Controllers.Api.Abstracts;
using GICS.Web.Managers.Interfaces;
using GICS.Web.Services.Interfaces;
using System.Collections.Generic;
using GICS.Web.ViewModels.Tenant;
using GICS.Web.Models.Tenant;
namespace GICS.Web.Controllers.Api
{
[RoutePrefix("api/tenant")]
public class TenantController : BaseApiController
{
private readonly ITenantManager _tenantsManager;
private readonly IRemedyService _remedyService;
private string token;
public TenantController(ITenantManager tenantsManager, IRemedyService remedyService)
{
_tenantsManager = tenantsManager;
_remedyService = remedyService;
token = null;
}
[HttpGet, Route("{groupId}/{userName}")]
public JsonResult getTenants(string groupId, string UserName)
{
getToken(UserName);
JsonResult result = Json(null);
if (token != null)
{
var tenants = _tenantsManager.GetTenants(token, groupId);
List<TenantViewModel> tenantViewModelList = new List<TenantViewModel>();
foreach (Values x in tenants)
{
TenantViewModel model = new TenantViewModel(x, groupId);
tenantViewModelList.Add(model);
}
result = Json(tenantViewModelList);
}
return result;
}
}
The TenantManager interface is as follows:
using System.Collections.Generic;
using GICS.Web.Models.Tenant;
namespace GICS.Web.Managers.Interfaces
{
public interface ITenantManager
{
IEnumerable<Values> GetTenants(string token, string groupId);
}
}
And the Manager implementation is:
using GICS.Web.Managers.Abstracts;
using GICS.Web.Managers.Interfaces;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Configuration;
using System.Net;
using GICS.Web.Models.Tenant;
namespace GICS.Web.Managers
{
public class TentantManager : ManagerBase, ITenantManager
{
public IEnumerable<Models.Tenant.Values> GetTenants(string token, string groupId)
{
Tenant restEntries = null;
List<Models.Tenant.Values> tenantList = new List<Models.Tenant.Values>();
using (WebClient client = new WebClient())
{
client.Headers[HttpRequestHeader.Authorization] = token;
var baseURL = ConfigurationManager.AppSettings["RemedyBaseUrl"];
var apiPath = ConfigurationManager.AppSettings["RemedyAPIPath"];
string getURL = baseURL + apiPath + "ESN%3AAST%3ALogSysComp%5FASTPeople" + "?q=?q=%27PeopleGroup%20Form%20Entry%20ID%27%20%3D%20%22" + groupId + "%22&fields=values(Name)";
string getResponse = client.DownloadString(getURL);
restEntries = JsonConvert.DeserializeObject<Tenant>(getResponse);
foreach (Models.Tenant.Entry x in restEntries.entries)
{
tenantList.Add(x.values);
}
}
return tenantList;
}
}
}
I have other controllers in the project that follow the same approach and all are working except for this one. Anyone spot where I am going wrong here?
Thanks in advance.
Good Day Everyone. I'm creating a simple Xamarin.Forms Portable Application in my Visual Studio 2015.
I want my Mobile Application to connect to the SQL Database I have in my VS2015 and return a LIST OF CUSTOMERS which should be display to my mobile phone.
I have created a Xamarin Portable project and a WebForms project that will handle my Web Services and Database.
In my WebForms project, I created a Controller that should return the List of Customers. This has a web service URL api/Customer that I used to connect to the RestClient in my Xamarin Portable. I also have CustomerViewModel that should represent the data in my application.
In my Xamarin Portable project, I have a ClientList.xaml that should display the List that comes from my database. I also have a CustomerVM that is connected to Services and my RestClient. My RestClient used the WEB SERVICE URL to get the List of Customer from my WebForms project.
Based on the given steps above, I still wasn't able to display the Data in my mobile phone. What do you think is the reason behind this? Thanks for your help.
Here are some of my codes:
RestClient.cs
public class RestClient_Customer<T>
{
private const string WebServiceUrl = "http://localhost:50857/api/Customer/";
public async Task<List<T>> GetCustomerAsync()
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var json = await httpClient.GetStringAsync(WebServiceUrl);
var taskModels = JsonConvert.DeserializeObject<List<T>>(json);
return taskModels;
}
}
CustomerServices.cs
using Plugin.RestClient;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using XamarinFormsDemo.Models;
namespace XamarinFormsDemo.Services
{
public class CustomerServices
{
public async Task<List<Customer>> GetCustomerAsync()
{
RestClient_Customer<Customer> restClient = new RestClient_Customer<Customer>();
var customerList = await restClient.GetCustomerAsync(); //yung getasync ay pantawag as restclient
return customerList;
}
}
}
CustomerVM.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using XamarinFormsDemo.Models;
using XamarinFormsDemo.Services;
using XamarinFormsDemo.Views;
namespace XamarinFormsDemo.ViewModels
{
public class CustomerVM : INotifyPropertyChanged
{
private List<Customer> _customerList; // keep all customers
private List<Customer> _searchedCustomerList; // keep a copy for searching
private Customer _selectedCustomer = new Customer();
private string _keyword = "";
public string Keyword
{
get
{
return _keyword;
}
set
{
this._keyword = value;
// while keyword changed we filter Employees
//Filter();
}
}
private void Filter()
{
if (string.IsNullOrWhiteSpace(_keyword))
{
CustomerList = _searchedCustomerList;
}
else
{
// var lowerKeyword = _keyword.ToLower();
CustomerList = _searchedCustomerList.Where(r => r.CUSTOMER_NAME.ToLower().Contains(_keyword.ToLower())).ToList();
// EmployeesList = _searchedEmployeesList.Where(r => r.EMPLOYEE_NAME.Contains(_keyword)).ToList();
}
}
public List<Customer> CustomerList
{
get
{
return _customerList;
}
set
{
_customerList = value;
OnPropertyChanged();
}
}
public CustomerVM()
{
InitializeDataAsync();
}
private async Task InitializeDataAsync()
{
var customerServices = new CustomerServices();
_searchedCustomerList = await customerServices.GetCustomerAsync();
CustomerList = await customerServices.GetCustomerAsync();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I think the problem is in your services hope this will help you,
public interface ICustomer
{
Task<string> GetCustomers();
}
public class CustomerService : ICustomer
{
public async Task<string> GetCustomers()
{
var client = new HttpClient();
var response = await client.GetAsync(string.Format("http://mysite/api/Customer"));
var responseString = await response.Content.ReadAsStringAsync();
return responseString;
}
}
Call it anywhere you like
var _custList = new GetCustomers();
var returnJson = await _custList.GetCustomers();
Note the return is json string format or xml format depending on your REST API so you need to parse this first before you can get the value and display it to ListView
Try running it in UWP. If it works in UWP then you have to take a look at
Xamarin HttpClient.GetStringAsync not working on Xamarin.Droid
I had the same issue but when I tried it in UWP it worked fine. I am still seeking for the solution to run xamarin.android using device.
Update: HttpTest is not thread-safe, as per the project's GitHub issue. Until the issue is resolved, tests using HttpTest cannot be run in parallel.
I have a really weird pair of test utilizing Flurl and xUnit that, when Run All in VS Test Explorer, will fail, but if run individually, will pass. I cannot for the life of me see anywhere where the 2 are even related to each other, but they do.
I have extracted them out of my project into a new project and the problem persists. I bundled them into a 7z for anyone interested in loading it to VS, but the full code follows.
Project.Commons
GetApi1:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Flurl;
using Flurl.Http;
namespace Project.Commons
{
public class GetApi1
{
public async Task<string> ExecuteAsync(string token)
{
string apikeyKeyname = "token";
dynamic response = await "http://www.api.com"
.SetQueryParams(new { token = token })
.GetJsonAsync();
string receivedApiKey = ((IDictionary<string, object>)response)[apikeyKeyname].ToString();
return receivedApiKey;
}
}
}
GetApi2:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Flurl;
using Flurl.Http;
namespace Project.Commons
{
public class GetApi2
{
public async Task<IList<string>> ExecuteAsync()
{
var responses = await "http://www.api.com"
.GetJsonAsync<List<string>>();
var result = new List<string>();
foreach (var response in responses)
{
result.Add("refined stuff");
}
return result;
}
}
}
Project.Tests
UnitTest1:
using Project.Commons;
namespace Project.Tests
{
public class UnitTest1
{
private ITestOutputHelper output;
public UnitTest1(ITestOutputHelper output)
{
this.output = output;
}
[Fact]
public async Task ShouldBeAbleToGetApiKeyFromToken()
{
// Arrange
using (var httpTest = new HttpTest())
{
var jsonResponse = new { token = "abcdef" };
string expectedApiKey = "abcdef";
httpTest.RespondWithJson(jsonResponse);
var api = new GetApi1();
// Act
var receivedApiKey = await api.ExecuteAsync("mockToken");
output.WriteLine("Received apikey = " + receivedApiKey);
// Assert
Assert.Equal(expectedApiKey, receivedApiKey);
}
}
}
}
UnitTest2
using Flurl.Http.Testing;
using Project.Commons;
using Xunit;
using Xunit.Abstractions;
namespace Project.Tests
{
public class UnitTest2
{
#region Mock API JSON Response
private IList<string> mockResponse = new List<string>()
{
"raw stuff", "raw stuff", "raw stuff"
};
#endregion
#region Expected Result
private IList<string> expectedResult = new List<string>()
{
"refined stuff", "refined stuff", "refined stuff"
};
#endregion
[Fact]
public async Task CanGetProjectsByWeek()
{
// Arrange
using (var httpTest = new HttpTest())
{
httpTest.RespondWithJson(mockResponse);
// Act
var api = new GetApi2();
var actualResult = await api.ExecuteAsync();
// Assert
Assert.Equal(expectedResult,actualResult);
}
}
}
}
The comments are correct - lack of thread safety is a known limitation of HttpTest. It is logged and under investigation. Parallel testing is much more prevalent today than just a couple years ago when this was created, so while a fix is not trivial, we are treating it with high priority.
I'm trying to implement the use of Google Drive in my app but I seem to be getting the following error "Method 'get_Error' in type 'Google.Apis.Drive.v2.Data.FileList' from assembly 'Google.Apis.Drive.v2, Version=1.2.4647.29713, Culture=neutral, PublicKeyToken=null' does not have an implementation". Does anyone know as to why this is occurring? I based my code on the example that Google provides for its tasks API.
Code below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Util;
using System.Diagnostics;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth2;
using Google.Apis.Authentication;
using Google.Apis.Authentication.OAuth2;
using Google.Apis.Authentication.OAuth2.DotNetOpenAuth;
using Google.Apis.Util;
using PrepHub.PrepHub;
using System.Web.Services;
using System.Threading;
using Google.Apis;
using Google.Apis.Drive.v2.Data;
using Google.Apis.Drive.v2;
using Google.Apis.Drive;
namespace DriveExample
{
public partial class GDrive : System.Web.UI.Page
{
private static DriveService _service; // We don't need individual service instances for each client.
private OAuth2Authenticator<WebServerClient> _authenticator;
private IAuthorizationState _state;
private IAuthorizationState AuthState
{
get
{
return _state ?? HttpContext.Current.Session["AUTH_STATE"] as IAuthorizationState;
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (_service == null)
{
_service = new DriveService(_authenticator = CreateAuthenticator());
}
if (HttpContext.Current.Request["code"] != null)
{
_authenticator = CreateAuthenticator();
_authenticator.LoadAccessToken();
}
var ni = _service.Files.List().Fetch();
}
private OAuth2Authenticator<WebServerClient> CreateAuthenticator()
{
var provider = new WebServerClient(GoogleAuthenticationServer.Description);
provider.ClientIdentifier = ClientCredentials.ClientID;
provider.ClientSecret = ClientCredentials.ClientSecret;
var authenticator =
new OAuth2Authenticator<WebServerClient>(provider, GetAuthorization) { NoCaching = true };
return authenticator;
}
private IAuthorizationState GetAuthorization(WebServerClient client)
{
// If this user is already authenticated, then just return the auth state.
IAuthorizationState state = AuthState;
if (state != null)
{
return state;
}
// Check if an authorization request already is in progress.
state = client.ProcessUserAuthorization(new HttpRequestInfo(HttpContext.Current.Request));
if (state != null && (!string.IsNullOrEmpty(state.AccessToken) || !string.IsNullOrEmpty(state.RefreshToken)))
{
// Store and return the credentials.
HttpContext.Current.Session["AUTH_STATE"] = _state = state;
return state;
}
string scope = DriveService.Scopes.Drive.GetStringValue();
OutgoingWebResponse response = client.PrepareRequestUserAuthorization(new[] { scope });
response.Send();
return null;
}
}
}
I'm guessing some of your assemblies are out of date. That error will occur when you have an assembly for example, lets say foo.dll (v1) and that assembly is being referenced by bar.dll (v2). A class in bar.dll is expecting something in to be present on a class in Foo and its not there. In your case, its the get accessor for a property called Error on the class FileList. Double check all your assemblies to make sure they are all at their most recent version (s).