How can I remove the hard coding of the web service address from .ClientConfig files - silverlight

I have 5 SilverLight projects in my ASP .NET MVC 4 application. For each of these projects, there is a web service which passes data to and from the silverlight control.
When we deploy the application on the client's server, we update the .ClientConfig file of each SilverLight project by changing the address of the web service.
That is we change -
<endpoint address="http://localhost:52213/SchemeReimbursementMasterService.asmx"
binding="basicHttpBinding" bindingConfiguration="SchemeReimbursementMasterServiceSoap"
contract="SchemeServiceReference.SchemeReimbursementMasterServiceSoap"
name="SchemeReimbursementMasterServiceSoap" />
to -
<endpoint address="http://192.168.5.48/SCHEME/SchemeReimbursementMasterService.asmx"
binding="basicHttpBinding" bindingConfiguration="SchemeReimbursementMasterServiceSoap"
contract="SchemeServiceReference.SchemeReimbursementMasterServiceSoap"
name="SchemeReimbursementMasterServiceSoap" />
Then we build it and publish the application.
So, in future, if the address changes, we would have to change it in all the five .ClientConfig files and build/publish it again. Is there any way we can remove this hardcoding so that it figures out the base part of the url (i.e: http://192.168.5.48/SCHEME/) on its own.

In my application's web.config, I added keys for the service names.
<appSettings>
<add key="ReviewUrl" value="ReviewClaimsService.asmx"/>
<add key="ReimbursementUrl" value="SchemeReimbursementMasterService.asmx"/>
<add key="DiscountUrl" value="DiscountMasterSchemeService.asmx"/>
</appSettings>
In the controller, I created the URL using the HttpContext and the service name from web.config and passed it to the view.
var baseUrl = "http://" + HttpContext.Request.Headers["Host"];
var applicationPath = HttpContext.Request.ApplicationPath;
if (applicationPath == "/")
baseUrl = baseUrl + "/";
var url = baseUrl + ConfigurationManager.AppSettings["ReimbursementUrl"];
In the View, I passed this URL to the silverlight control using InitParams.
<object id="TownsGrid" data="data:application/x-silverlight-2," type="application/x-silverlight-2">
<param name="InitParams" value="ControlName=TownDataGrid,ServiceUrl=#Model.ServiceUrl" />
<param name="source" value="#Url.Content("~/ClientBin/SilverlightApplication.xap")"/>
</object>
In the Application_Startup method of the silverlight project, I passed the URL on to the SilverLight control.
private void Application_Startup(object sender, StartupEventArgs e)
{
var url = e.InitParams["ServiceUrl"];
this.RootVisual = new SilverlightApplication.TownDataGrid(url);
}
And finally, in the silverlight control, I assign the url to the endpoint.
public TownDataGrid(string serviceUrl)
{
InitializeComponent();
EndpointAddress endpoint = new EndpointAddress(serviceUrl);
BasicHttpBinding binding = new BasicHttpBinding();
client = new SchemeReimbursementMasterServiceSoapClient(binding,endpoint);
}

Related

Why cannot write log to files when WPF application publishing as a single file

I use Microsoft.Extensions.Hosting and NLog.Web.AspNetCore in WPF. The application run correctly with Debug and Release mode, But when I publish the app as a single file, I found File target does not work when fileName using relative path.
NLog version: 4.6.8
Platform: .NET Core 3
NLog config
<nlog>
<targets>
<default-wrapper xsi:type="BufferingWrapper" bufferSize="100"/>
<target xsi:type="File" name="file" fileName="logs/${level}-${shortdate}.log" encoding="utf-8"
layout="${longdate}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="file" final="true"/>
</rules>
</nlog>
I use AddNLog to apply this configuration:
public App()
{
_host = new HostBuilder()
.ConfigureLogging(logBuilder =>
{
logBuilder.ClearProviders()
.SetMinimumLevel(LogLevel.Debug)
.AddNLog("NLog.config");
})
.ConfigureServices((hostContext, services) =>
{
//...
}).Build();
}
Show the MainWindow when application startup:
private void Application_Startup(object sender, StartupEventArgs e)
{
using var serviceScope = _host.Services.CreateScope();
var serviceProvider = serviceScope.ServiceProvider;
_logger = serviceProvider.GetRequiredService<ILogger<App>>();
SetupExceptionHandling();
MainWindow mainWindow = serviceProvider.GetRequiredService<MainWindow>();
mainWindow.Show();
_logger.LogInformation($"Application startup at {DateTime.Now} successfully");
}
Publishing as a single file and run it, the log of successful startup is not written to the file, But when i change fileName to an absolute path like /logs/${level}-${shortdate}.log or ${level}-${shortdate}.log, the log can be written.
I try to configure it in code:
var config = new LoggingConfiguration();
var file = new FileTarget("file")
{
FileName = "logs/${shortdate}-${level}.log",
Layout = "${longdate}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}"
};
config.AddRule(LogLevel.Info, LogLevel.Fatal, new BufferingTargetWrapper(file));
return config;
But the result is still the same.
Am I writing something wrong? thanks for your help.
NLog will automatically prefix relative fileName-path with the ${basedir}-layout. See also https://github.com/nlog/nlog/wiki/Basedir-Layout-Renderer
Sadly enough Microsoft decided not to fix AppDomain.BaseDirectory when doing Single File Publish in NetCore 3.1
https://github.com/dotnet/aspnetcore/issues/12621
https://github.com/dotnet/core-setup/issues/7491
The work-around is to explictly specify ${basedir:fixTempDir=true}:
<nlog>
<targets>
<default-wrapper xsi:type="BufferingWrapper" bufferSize="100"/>
<target xsi:type="File" name="file" fileName="${basedir:fixtempdir=true}/logs/${level}-${shortdate}.log" encoding="utf-8"
layout="${longdate}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="file" final="true"/>
</rules>
</nlog>
Hopefully Microsoft will fix the illusion with NetCore5

How do I prevent SimpleSecurityManager being used in JackRabbit?

How I stop Jackrabbit using SimpleSecurityManager?
I'm trying to call session.getUserManager() but I get a repository exception as SimpleSecurityManager.getUserManager() explicity throws it.
<Security appName="Jackrabbit">
<SecurityManager class="org.apache.jackrabbit.core.DefaultSecurityManager" workspaceName="security">
</SecurityManager>
<AccessManager class="org.apache.jackrabbit.core.security.simple.SimpleAccessManager">
<!-- <param name="config" value="${rep.home}/access.xml"/> -->
</AccessManager>
<LoginModule class="org.apache.jackrabbit.core.security.authentication.DefaultLoginModule">
<param name="anonymousId" value="anonymous"/>
<param name="adminId" value="admin"/>
</LoginModule>
</Security>
Rest of code for those that will ask...
Repository repository = new TransientRepository();
Session jackrabbitSession = repository.login(credentials);
UserManager userManager = session.getUserManager();
The user manager is a Jackrabbit extension. It's not a part of the JCR. So, you need to use a JackrabbitSession, not just a Session. Here's a link to the wiki:
http://wiki.apache.org/jackrabbit/UserManagement

Fun with "The remote server returned an error: NotFound" - Silverlight4 Out of Browser

I'm running SL4 on VS2010. I've got an app that authenticates via a web service to SPROC in my db. Unfortunately this is not WCF/WCF RIA, as I'm inheriting the DB/services from my client.
This works perfectly inside of a browser (via HTTPS). I'm attempting to move this OOB, and it's at this point that my authentication fails. Here's the steps I took...
1) SL App Properties > Enable running app Out of Browser
2) SL App Properties > Out of Browser Settings > Require elevated trust when running OOB
If i set a breakpoint on my logon button click, I see the service call is being made. However, if I step through it (or set a breakpoint on the actual logon web service), the code never gets that far. Here's the block it fails on:
public LogonSVC.LogonResponse EndLogon(System.IAsyncResult result) {
object[] _args = new object[0];
LogonSVC.LogonResponse _result = ((LogonSVC.LogonResponse)(base.EndInvoke("Logon", _args, result)));
return _result;
}
I know using Elevated Trust means the crossdomain.xml isn't necessary. I dropped one in that allows everything, just to test, and that still fails.
here's the code that calls the service:
private void loginButton_Click(object sender, RoutedEventArgs e)
{
string Username = txtUserName.Text;
string Password = txtPassword.Password;
Uri iSilverlightServiceUriRelative = new Uri(App.Current.Host.Source, "../Services/Logon.asmx");
EndpointAddress iSilverlightServiceEndpoint = new EndpointAddress(iSilverlightServiceUriRelative);
BasicHttpBinding iSilverlightServiceBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);// Transport if it's HTTPS://
LogonService = new LogonSVC.LogonSoapClient(iSilverlightServiceBinding, iSilverlightServiceEndpoint);
LogonService.LogonCompleted += new EventHandler<LogonSVC.LogonCompletedEventArgs>(LogonService_LogonCompleted);
LogonService.LogonAsync(Username, Password);
}
My LogonService_LogonCompleted doesn't fire either (which makes sense, just a heads up).
I don't know how to fiddler this, as this is running OOB with the site served via localhost/IIS. I know this works though in browser, so I'm curious what would break it OOB.
UPDATE
I changed my ServiceReferences.ClientConfig to relative URLs instead of absolute, at the recommendation of another post I read. Here's the code:
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="CommonSoap" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
<security mode="Transport" />
</binding>
<binding name="LogonSoap" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="/Services/Common.asmx"
binding="basicHttpBinding" bindingConfiguration="CommonSoap"
contract="CommonSVC.CommonSoap" name="CommonSoap" />
<endpoint address="/Services/Logon.asmx"
binding="basicHttpBinding" bindingConfiguration="LogonSoap"
contract="LogonSVC.LogonSoap" name="LogonSoap" />
</client>
</system.serviceModel>
UPDATE 2
Stack trace, if it helps anyone...
at System.ServiceModel.AsyncResult.End[TAsyncResult](IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
at System.ServiceModel.ClientBase`1.ChannelBase`1.EndInvoke(String methodName, Object[] args, IAsyncResult result)
at TSMVVM.TSMVVMLogonSVC.LogonSoapClient.LogonSoapClientChannel.EndLogon(IAsyncResult result)
at TSMVVM.TSMVVMLogonSVC.LogonSoapClient.TSMVVM.TSMVVMLogonSVC.LogonSoap.EndLogon(IAsyncResult result)
at TSMVVM.TSMVVMLogonSVC.LogonSoapClient.EndLogon(IAsyncResult result)
at TSMVVM.TSMVVMLogonSVC.LogonSoapClient.OnEndLogon(IAsyncResult result)
at System.ServiceModel.ClientBase`1.OnAsyncCallCompleted(IAsyncResult result)
Thank you,
Scott
I'm not allowed to comment so I'll have to post this question as an answer
Is it because Silverlight treats all http error codes other than 200 as a 404.
Use fiddler to check the response status code and try an http handler to change it to a 200. This was a common problem in silverlight 2 which I thought they'd fixed but maybe the fix was only for WCF and RIA services.

WCF PollingDuplexHttpBinding with Silverlight Client timeouts and errors

Im building a WPF 3.5 desktop app that has a self-hosted WCF service.
The service has an PollingDuplexHttpBinding endpoint defined like so:
public static void StartService()
{
var selfHost = new ServiceHost(Singleton, new Uri("http://localhost:1155/"));
selfHost.AddServiceEndpoint(
typeof(IMyService),
new PollingDuplexHttpBinding(PollingDuplexMode.MultipleMessagesPerPoll) {ReceiveTimeout = new TimeSpan(1,0,0,0)},
"MyService"
);
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
selfHost.Description.Behaviors.Add(smb);
selfHost.AddServiceEndpoint(typeof(IPolicyRetriever), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
selfHost.Open();
}
Note: the IPolicyRetriever is a service that enables me to define a policy file
This works and I can see my service in my client Silverlight application. I then create a reference to the proxy in the Silverlight code like so:
EndpointAddress address = new EndpointAddress("http://localhost:1155/MyService");
PollingDuplexHttpBinding binding = new PollingDuplexHttpBinding(PollingDuplexMode.MultipleMessagesPerPoll);
binding.ReceiveTimeout = new TimeSpan(1, 0, 0, 0);
_proxy = new MyServiceClient(binding, address);
_proxy.ReceiveReceived += MessageFromServer;
_proxy.OrderAsync("Test", 4);
And this also works fine, the communication works!
But if I leave it alone (i.e. dont sent messages from the server) for longer than 1 minute, then try to send a message to the client from the WPF server application, I get timeout errors like so:
The IOutputChannel timed out attempting to send after 00:01:00. Increase the timeout value passed to the call to Send or increase the SendTimeout value on the Binding. The time allotted to this operation may have been a portion of a longer timeout.
Its all running on localhost and there really should not be a delay, let alone a 1 minute delay. I dont know why, but the channel seems to be closed or lost or something...
I have also tried removing the timeouts on the bindings and I get errors like this
The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it has been Aborted
How can I try to find out whats wrong here?
WPF uses wsDualHttpBinding, Silverlight - Polling Duplex.
WPF solution is simple; Silverlight requires ServiceHostFactory and a bit more code. Also, Silverlight Server never sends messages, rather Client polls the server and retrieves its messages.
After many problems with PollingDuplexHttpBinding I have decided to use CustomBinding without MultipleMessagesPerPoll.
web.config
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="SlApp.Web.DuplexServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service behaviorConfiguration="SlApp.Web.DuplexServiceBehavior" name="SlApp.Web.DuplexService">
<endpoint address="WS" binding="wsDualHttpBinding" contract="SlApp.Web.DuplexService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
DuplexService.svc:
<%# ServiceHost Language="C#" Debug="true" Service="SlApp.Web.DuplexService" Factory="SlApp.Web.DuplexServiceHostFactory" %>
DuplexServiceHostFactory.cs:
public class DuplexServiceHostFactory : ServiceHostFactoryBase
{
public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
return new DuplexServiceHost(baseAddresses);
}
}
class DuplexServiceHost : ServiceHost
{
public DuplexServiceHost(params Uri[] addresses)
{
base.InitializeDescription(typeof(DuplexService), new UriSchemeKeyedCollection(addresses));
}
protected override void InitializeRuntime()
{
PollingDuplexBindingElement pdbe = new PollingDuplexBindingElement()
{
ServerPollTimeout = TimeSpan.FromSeconds(3),
//Duration to wait before the channel is closed due to inactivity
InactivityTimeout = TimeSpan.FromHours(24)
};
this.AddServiceEndpoint(typeof(DuplexService),
new CustomBinding(
pdbe,
new BinaryMessageEncodingBindingElement(),
new HttpTransportBindingElement()), string.Empty);
base.InitializeRuntime();
}
}
Silverlight client code:
address = new EndpointAddress("http://localhost:43000/DuplexService.svc");
binding = new CustomBinding(
new PollingDuplexBindingElement(),
new BinaryMessageEncodingBindingElement(),
new HttpTransportBindingElement()
);
proxy = new DuplexServiceClient(binding, address);

Self hosted WCF not reachable

Hi guys I just want a simple WinForm app with one button. When I press the button
i want to start the selfhosted WCF service. I want to able to connect to this service with for example another client app (winforms) by just adding a service reference.
However the solution that I created is not working. I can't get connected with adding a service reference to this service. I don't actually know what address to call than except the address that I defined in the app.config file. Any help would be great.
Here is the app.config file.
<configuration>
<system.serviceModel>
<services>
<service name="WindowsFormsApplication11.WmsStatService">
<endpoint address="http://192.168.0.197:87" binding="basicHttpBinding"
bindingConfiguration="" contract="WindowsFormsApplication11.IWmsStat"/>
</service>
</services>
</system.serviceModel>
</configuration>
And forms code:
namespace WindowsFormsApplication11
{
public partial class Form1 : Form
{
public ServiceHost _host = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
_host = new ServiceHost(typeof(WmsStatService));
_host.Open();
}
}
// Define a service contract.
[ServiceContract(Namespace = "http://WindowsFormsApplication11")]
public interface IWmsStat
{
[OperationContract]
string sayHello(string name);
}
public class WmsStatService : IWmsStat
{
public string sayHello(string name)
{
return "hello there " + name + " nice to meet you!";
}
}
}
I changed the app.config file. The problem is solved. Also thanks for the tips and your answers. The config is changed to.
<configuration>
<system.serviceModel>
<services>
<service name="WindowsFormsApplication11.WmsStatService" behaviorConfiguration="mex">
<host>
<baseAddresses>
<add baseAddress="http://192.168.0.197:87/" />
</baseAddresses>
</host>
<endpoint address="http://192.168.0.197:87/Test" binding="basicHttpBinding" bindingConfiguration="" contract="WindowsFormsApplication11.IWmsStat" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="mex">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
The host should open on http://192.168.0.197:81 as in the config file.
So once the host is up and running then, try and broswe to it using the service reference.
I assume that the address is that your machine, and you don't have anything else on that port address. The other things to check are firewalls blocking that port.
I would not have the service class that implements the service contract (interface) be the form - make it a separate interface, a separate class. The reasoning behind this is the fact that the service host will have to create (instantiate) one instance of the service class for each request it needs to handle --> make those classes as small as possible and don't bloat them by baggage (like the Winform) that they don't need for their job!
Then instantiate a ServiceHost inside your Winform - but make that a global member variable of the form! Otherwise, the ServiceHost is gone once your ButtonClick event is finished!
// Define a service contract.
[ServiceContract(Namespace = "http://WindowsFormsApplication11")]
public interface IWmsStat
{
[OperationContract]
string sayHello(string name);
}
public class YourServiceClass : IWmsStat
{
public string sayHello(string name)
{
return "hello there " + name + " nice to meet you!";
}
}
public partial class Form1 : Form
{
private ServiceHost _host = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
_host = new ServiceHost(typeof(YourServiceClass));
// Open the ServiceHostBase to create listeners and start
// listening for messages.
_host.Open();
}
Don't mix the class that contains the ServiceHost, with the ServiceClass (which will need to be instantiated by the host to satisfy incoming requests) - the Service implementation should be standalone, and as lean as possible!
Also, it's good practice to follow the Single Responsability Principle - one class should have one job and one job only - don't pack up your whole app logic into a single, huge class - separate out the different jobs into separate classes and compose those together.
Marc

Resources