Android Studio 3.1
Here my Retrofit init:
private static Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(BuildConfig.API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.client(httpClient.build());
private static Retrofit retrofit = builder.build();
public static <T> T createRestClient(Class<T> restClientClass) {
retrofit = builder.build();
return retrofit.create(restClientClass);
}
public static Retrofit getRetrofit() {
return retrofit;
}
The API_BASE_URL I set in gradle.properties:
DEBUG_API_BASE_URL=\"http://myhost.com/\"
Nice. It's work fine.
But sometime, e.g. when I run tests, I need to change baseUrl.
To do this I change production url in DEBUG_API_BASE_URL in file gradle.properties to test url.
After finish tests I return production url in file gradle.properties.
It's work. But I think it's not good solution.
Is it possible to change in runtime the baseUrl for Retrofit?
If you are using Android (unclear from the question), you can use different buildTypes. See https://developer.android.com/studio/build/gradle-tips section "Share custom fields and resource values with your app's code"
android {
...
buildTypes {
release {
buildConfigField("String", "API_BASE_URL", \"http://www.myhost.com/\")
}
debug {
buildConfigField("String", "API_BASE_URL", \"http://staging.myhost.com/\")
}
}
}
Related
I'm trying to find a simple way to access a value from the configuration of a .NET 6, ASP.NET Core Web App, in a Razor page's .cs file, using Visual Studio 2022. There's a lot of examples of how to do this online the old way. I'm trying to get up to speed with ASP.NET Core, and .NET 6, and I don't want to use the old techniques.
Right now I can connect to a SQLite database with a very simple configuration. Here's the code in my Index.cshtml.cs file,
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Configuration;
using System.Data.SQLite;
namespace Something.Pages
{
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
public void OnGet()
{
var cnnStrBuilder = new SQLiteConnectonStringBuilder();
cnnStrBuild.DataSource = "DBFile.SQLite";
using (SQLiteConnection cnn = new(cnnStrBuilder.ConnectionString))
{
cnn.Open();
...
}
}
}
}
This works. I can read and display data without the need for a DBContext, or EntityFramework, or anything else. All I want to change is to get the connection string from the appsettings.json file. My appsettings.json looks like this,
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"MyConStr" : "DBFile.SQLite"
},
"AllowedHosts": "*"
}
in my Program.cs file is the builder object, which I could use to get the configuration.
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
but how do I get access to the builder object in the Razor page's .cs file so I can get to the configuration? .NET 6 is supposed to make things like this easier, I thought.
BTW, I purposefully left 'connection string' out of the title of this post because I feel like this should be a generic thing. It shouldn't be so hard to retrieve a string value from the configuration settings from anywhere in the application. What am I missing?
You can inject an instance of IConfiguration in your PageModel which you can use to access appsettings.json values.
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
private readonly IConfiguration _configuration;
public IndexModel(ILogger<IndexModel> logger, IConfiguration configuration)
{
_logger = logger;
_configuration = configuration;
}
public void OnGet()
{
var cnnStrBuilder = new SQLiteConnectonStringBuilder();
cnnStrBuild.DataSource = _configuration.GetConnectionString("MyConStr");
using (SQLiteConnection cnn = new(cnnStrBuilder.ConnectionString))
{
cnn.Open();
...
}
}
}
You can also check this article for more info:
https://www.learnrazorpages.com/configuration/
I have this code in my project that I uploaded to Azure Web Job.
class Program {
static void Main(string[] args) {
var host = new JobHost();
host.RunAndBlock();
}
public static async Task AddSomethingAsync([QueueInput("myqueue1")] string _)
{
//....
}
public static async Task UpdateSomethingAsync([QueueInput("myqueue2")] string _)
{
//....
}
}
}
But it shows the first function "AddSomethingAsync" only in azure scm site (https://me.scm.azurewebsites.net/azurejobs/#/jobs/triggered/myjob/runs/201406170707442616)
Is it the known issue or Am I missing something?
Thanks!
Okie. I got it now. I need to go to Functions page to see it. The default shows only the first method.
I am implementing OWIN authentication on a mysql backend, I dont thnk thats a problem as my registration work pretty well. I have basically worked off this post (i.e. nicked most of the code).
I am also using DI via autofac so I have changed a few things around to inject dependencies into the SimpleAuthorizationServerProvider
THE PROBLEM
I post grant_type=password, username and password to http://localhost/myappurl/token and I get back "error":"invalid_client". I get no hits when I try to debug so its probably failing in the library and not getting to my own code. Does anyone know why this would be?
Please pardon the lengthy code, I have no idea where the issue could be so I have posted everything I think is relevant, if anyone needs to see more code, please ask.
SimpleAuthorizationServerProvider
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
private readonly IUserService _userService;
public SimpleAuthorizationServerProvider(IUserService userService)
{
_userService = userService;
}
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
var authenticate = await _userService.FindUser(context.UserName, context.Password);
if (!authenticate)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
}
Startup
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuth(app, (IOAuthAuthorizationServerProvider)config.DependencyResolver.GetService(typeof(IOAuthAuthorizationServerProvider)));
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app, IOAuthAuthorizationServerProvider provider)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(90),
Provider = provider,
ApplicationCanDisplayErrors=true,
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
IocConfig
public static class IocConfig
{
public static void Register(HttpConfiguration config)
{
var builder = new ContainerBuilder();
// Configure the container
// Register individual components
builder.Register(c => new MySQLContext()).As<IMySqlContext>().InstancePerRequest();
builder.RegisterType<SimpleAuthorizationServerProvider>().As<IOAuthAuthorizationServerProvider>();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
}
You have a lot of code there, so it's not easy to isolate the problem. As a first step, consider removing the code for Autofac DI and see if that makes any difference. It's hard to tell what the problem might be otherwise.
If the issue is indeed related to the DI code, then perhaps this should be a raised as a separate question. In that case, try to create a small code example that demonstrates the issue succinctly. People are more likely to help if the problem code is short and to the point.
Make sure that you've set up SSL for your site. I had a similar issue and the problem was that I was not using SSL.
I have CruiseControl.NET version 1.4.4.83, and I am wondering if there it provides a url where the only control is the lastest build # of a project, so that I can access that data using curl or something?
Something like http://buildserver/ccnet/server/VMSDEV2/project/MyProject/LatestBuild.aspx
All that it would have is:
0.0.0.31
Update:
Fixed the IPlugin issue with an attribute for the class:
[Exortech.NetReflector.ReflectorType("latestBuildNumberProjectPlugin")]
public class LatestBuildNumberProjectPlugin : ICruiseAction, IPlugin
{
public static readonly string ACTION_NAME;
private readonly IFarmService farmService;
private readonly ILinkFactory linkFactory;
static LatestBuildNumberProjectPlugin()
{
ACTION_NAME = "LatestBuildNumber";
}
public LatestBuildNumberProjectPlugin(IFarmService farmService, ILinkFactory linkFactory)
{
this.farmService = farmService;
this.linkFactory = linkFactory;
}
public IResponse Execute(ICruiseRequest cruiseRequest)
{
IProjectSpecifier projectSpecifier = cruiseRequest.ProjectSpecifier;
IBuildSpecifier[] mostRecentBuildSpecifiers = this.farmService.GetMostRecentBuildSpecifiers(projectSpecifier, 1);
if (mostRecentBuildSpecifiers.Length == 1)
{
var build = mostRecentBuildSpecifiers[0].BuildName;
var response = new HtmlFragmentResponse(build);
return response;
}
return new HtmlFragmentResponse("There are no complete builds for this project");
}
public INamedAction[] NamedActions
{
get
{
return new INamedAction[] { new ImmutableNamedAction(ACTION_NAME, this) };
}
}
public string LinkDescription
{
get { return "Latest Build Number"; }
}
}
And I've named my assembly:
ccnet.latestBuildNumberProjectPlugin.plugin.dll
And in the dashboard.config file, I've added the plugin ref:
<projectPlugins>
...
<latestBuildReportProjectPlugin />
...
</projectPlugins>
But apparently, var build = mostRecentBuildSpecifiers[0].BuildName; is not what I am looking for.
I believe it is possible to create packages to extend the CC.NET Dashboard (i.e. the website) and completely change the interface.
To help you get started, check the CC.NET documentation.
A few links that could be of help.
- Developing Web Dashboard Plugins
- Building Packages
- Configuring the Web Dashboard
HTH,
The link to the latest build is:
http://myserver.com/cc_net/server/local/project/myproject/ViewLatestBuildReport.aspx
it will expand in :
http://myserver.com/cc_net/server/local/project/myproject/build/log20100618165244Lbuild.45.xml/ViewBuildReport.aspx
Inside the html page, you have your build number.
I wrote about this topic in another question.
However, I've since refactored my code to get rid of configuration access, thus allowing the specs to pass. Or so I thought. They run fine from within Visual Studio using TestDriven.Net. However, when I run them during rake using the mspec.exe tool, they still fail with a serialization exception. So I've created a completely self-contained example that does basically nothing except setup fake security credentials on the thread. This test passes just fine in TD.Net, but blows up in mspec.exe. Does anybody have any suggestions?
Update: I've discovered a work-around. After researching the issue, it seems the cause is that the assembly containing my principal object is not in the same folder as the mspec.exe. When mspec creates a new AppDomain to run my specs, that new AppDomain has to load the assembly with the principal object in order to deserialize it. That assembly is not in the same folder as the mspec EXE, so it fails. If I copied my assembly into the same folder as mspec, it works fine.
What I still don't understand is why ReSharper and TD.Net can run the test just fine? Do they not use mspec.exe to actually run the tests?
using System;
using System.Security.Principal;
using System.Threading;
using Machine.Specifications;
namespace MSpecTest
{
[Subject(typeof(MyViewModel))]
public class When_security_credentials_are_faked
{
static MyViewModel SUT;
Establish context = SetupFakeSecurityCredentials;
Because of = () =>
SUT = new MyViewModel();
It should_be_initialized = () =>
SUT.Initialized.ShouldBeTrue();
static void SetupFakeSecurityCredentials()
{
Thread.CurrentPrincipal = CreatePrincipal(CreateIdentity());
}
static MyIdentity CreateIdentity()
{
return new MyIdentity(Environment.UserName, "None", true);
}
static MyPrincipal CreatePrincipal(MyIdentity identity)
{
return new MyPrincipal(identity);
}
}
public class MyViewModel
{
public MyViewModel()
{
Initialized = true;
}
public bool Initialized { get; set; }
}
[Serializable]
public class MyPrincipal : IPrincipal
{
private readonly MyIdentity _identity;
public MyPrincipal(MyIdentity identity)
{
_identity = identity;
}
public bool IsInRole(string role)
{
return true;
}
public IIdentity Identity
{
get { return _identity; }
}
}
[Serializable]
public class MyIdentity : IIdentity
{
private readonly string _name;
private readonly string _authenticationType;
private readonly bool _isAuthenticated;
public MyIdentity(string name, string authenticationType, bool isAuthenticated)
{
_name = name;
_isAuthenticated = isAuthenticated;
_authenticationType = authenticationType;
}
public string Name
{
get { return _name; }
}
public string AuthenticationType
{
get { return _authenticationType; }
}
public bool IsAuthenticated
{
get { return _isAuthenticated; }
}
}
}
Dan,
thank you for providing a reproduction.
First off, the console runner works differently than the TestDriven.NET and ReSharper runners. Basically, the console runner has to perform a lot more setup work in that it creates a new AppDomain (plus configuration) for every assembly that is run. This is required to load the .dll.config file for your spec assembly.
Per spec assembly, two AppDomains are created:
The first AppDomain (Console) is created
implicitly when mspec.exe is
executed,
a second AppDomain is created by mspec.exe for the assembly containing the specs (Spec).
Both AppDomains communicate with each other through .NET Remoting: For example, when a spec is executed in the Spec AppDomain, it notifies the Console AppDomain of that fact. When Console receives the notification it acts accordingly by writing the spec information to the console.
This communiciation between Spec and Console is realized transparently through .NET Remoting. One property of .NET Remoting is that some properties of the calling AppDomain (Spec) are automatically included when sending notifications to the target AppDomain (Console). Thread.CurrentPrincipal is such a property. You can read more about that here: http://sontek.vox.com/library/post/re-iprincipal-iidentity-ihttpmodule-serializable.html
The context you provide will run in the Spec AppDomain. You set Thread.CurrentPrincipal in the Because. After Because ran, a notification will be issued to the Console AppDomain. The notification will include your custom MyPrincipal that the receiving Console AppDomain tries to deserialize. It cannot do that since it doesn't know about your spec assembly (as it is not included in its private bin path).
This is why you had to put your spec assembly in the same folder as mspec.exe.
There are two possible workarounds:
Derive MyPrincipal and MyIdentity from MarshalByRefObject so that they can take part in cross-AppDomain communication through a proxy (instead of being serialized)
Set Thread.CurrentPrincipal transiently in the Because
(Text is required for formatting to work -- please ignore)
Because of = () =>
{
var previousPrincipal = Thread.CurrentPrincipal;
try
{
Thread.CurrentPrincipal = new MyPrincipal(...);
SUT = new MyViewModel();
}
finally
{
Thread.CurrentPrincipal = previousPrincipal;
}
}
ReSharper, for example, handles all the communication work for us. MSpec's ReSharper Runner can hook into the existing infrastructure (that, AFAIK, does not use .NET Remoting).