WCF with multiple services and - rest

I'm trying to create a WCF that serves multiple rest services in one assembly. To test it, I have created 2 services with the same content that serves two interfaces.
I'm able to get metadata using the url
localhost/testwebservice/services/Service1.svc?wsdl or
localhost/testwebservice/services/Service2.svc?wsdl
, but when I try to execute a method
localhost/testwebservice/services/Service1.svc/GetData/0
, I get a DestinationUnreachable error.
The web.config file is
<system.serviceModel>
<services>
<service behaviorConfiguration="ServiceBehavior" name="test.Services.Service1">
<endpoint address="" binding="webHttpBinding"
contract="test.Contracts.IService1" />
<endpoint address="mex" binding="mexHttpBinding" contract="test.Contracts.IService1" />
</service>
<service behaviorConfiguration="ServiceBehavior" name="test.Services.Service2">
<endpoint address="" binding="webHttpBinding"
contract="test.Contracts.IService2" />
<endpoint address="mex" binding="mexHttpBinding" contract="test.Contracts.IService2" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
</system.serviceModel>
Each .cs interface file is like this
namespace test.Contracts
{
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "GetData/{value}")]
string GetData(string value);
}
}
Each .svc file is like this
namespace test.Services
{
public class Service1 : IService1
{
public string GetData(string value)
{
return string.Format("You entered: {0}", value);
}
}
}
I also, would like to access the webservice as localhost/testwebservice/services/Service1 and localhost/testwebservice/services/service2, instead of using .svc, but I can not config the webservice in order to remove the .svc suffix. I have tried to use the address of the endpoint, but i'm not able to make it run.

Related

Adding a new record to DB, key is always zero

I have an existing App written using Microsoft Visual C++ 2017, ASP.NET, MVC 5.2.7.0, Entity Framework Version=5, DB is SQL Server. When I add a new record to my DB, the key (ParkID) that results is a zero and when I try and save the change. I get an error.
Cannot insert the value NULL into column 'ParkID', table 'N_CWBFM-20170818.dbo.Park'; column does not allow nulls. INSERT fails.
The database N_CWBFM-20170818 was downloaded from the HOST where my app runs.
Confession, this is a hobby, so I may not use the correct terminology and translating other ways of adding data to a DB to the method I am using.
Model
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace CWBFM.Models
{
public class Park
{
[Key]
public int ParkID { get; set; }
public bool ParkChangePending { get; set; } // change pending true/false
public int ParkChangeCount { get; set; } // Count the number of changes to this record
public int ParkPrevRec { get; set; } // points backwards to the previous version
public int ParkNextRec { get; set; } // ID of previous record
Omitted
DB Context
using CWBFM.Models;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
namespace CWBFM.DAL
{
public class CWBFMContext : DbContext
{
public DbSet<Park> Parks { get; set; }
public DbSet<Photo> Photo { get; set; }
public DbSet<StateFilter> StateFilters { get; set; }
Omitted
Controller
using System;
using System.Data;
using System.Linq;
using System.Web.Mvc;
using CWBFM.Models;
using CWBFM.DAL;
namespace CWBFM.Controllers
{
public class ParkController : BaseController
{
private CWBFMContext db = new CWBFMContext();
Omitted
// POST: /Park/Create
[HttpPost]
[Authorize]
public ActionResult ParkCreate(Park park)
{
setYesNo(); //set the values for the dropdown box (Yes, No, Unknown)
if (ModelState.IsValid)
{
park.ParkChangePending = false;
park.ParkChangeCount = 0;
park.ParkDateCreated = DateTime.Now;
park.ParkDateChange = DateTime.Now;
park.ParkCreatedBy = #User.Identity.Name;
park.ParkChangedBy = #User.Identity.Name;
park.ParkStatus = "N";
db.Parks.Add(park);
int stop = park.ParkID;
db.SaveChanges();
park.ParkRecID = "Park" + park.ParkID.ToString();
db.SaveChanges();
return RedirectToAction("ParkDetails", new { id=park.ParkID });
}
return View(park);
}
Config
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=152368
-->
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<!-- <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.6.1" />
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="2880" />
</authentication>
<pages>
<namespaces>
<add namespace="System.Web.Helpers" />
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages" />
<add namespace="Telerik.Web.Mvc.UI" />
</namespaces>
</pages>
<httpRuntime targetFramework="4.6.1" maxRequestLength="20971520" />
<!-- This will handle requests up to 20MB -->
<profile inherits="CWBFM.Models.MyUserProfile" defaultProvider="DefaultProvider">
<providers>
<clear />
<add name="DefaultProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
</providers>
</profile>
<!--<profile defaultProvider="DefaultProfileProvider">
<providers>
<add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
</providers>
</profile>-->
<membership defaultProvider="DefaultMembershipProvider">
<providers>
<add name="DefaultMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
</membership>
<roleManager enabled="true" defaultProvider="DefaultRoleProvider">
<providers>
<add connectionStringName="DefaultConnection" applicationName="/" name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</providers>
</roleManager>
<!--
If you are deploying to a cloud environment that has multiple web server instances,
you should change session state mode from "InProc" to "Custom". In addition,
change the connection string named "DefaultConnection" to connect to an instance
of SQL Server (including SQL Azure and SQL Compact) instead of to SQL Server Express.
-->
<sessionState mode="InProc" customProvider="DefaultSessionProvider">
<providers>
<add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" />
</providers>
</sessionState>
<httpHandlers>
<add verb="GET,HEAD" path="asset.axd" validate="false" type="Telerik.Web.Mvc.WebAssetHttpHandler, Telerik.Web.Mvc" />
</httpHandlers>
<httpModules>
<add name="CompilableFileModule" type="SassAndCoffee.CompilableFileModule" />
</httpModules>
</system.web>
<system.webServer>
<security>
<requestFiltering>
<!-- This will handle requests up to 1024MB (1GB) -->
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<remove name="asset" />
<add name="asset" preCondition="integratedMode" verb="GET,HEAD" path="asset.axd" type="Telerik.Web.Mvc.WebAssetHttpHandler, Telerik.Web.Mvc" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" /><remove name="OPTIONSVerbHandler" /><remove name="TRACEVerbHandler" /><add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /></handlers>
<modules>
<remove name="CompilableFileModule" />
<add name="CompilableFileModule" type="SassAndCoffee.CompilableFileModule" />
</modules>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v11.0" />
</parameters>
</defaultConnectionFactory>
</entityFramework>
<connectionStrings>
It dies on the save (db.SaveChanges();). A breakpoint at int stop = park.ParkID; shows that the ParkID is zero.
ParkID = 0
I have looked at several proposed solutions, but just can’t find one that works. Any suggestions. Could I have missed an update in my config when I changed to EF 5?
This can occur if the database was set up without an Identity column set on the PK, but EF will automatically expect an identity column on keys named "Id" or with the "Id" suffix on the class name. (I.e. Park.ParkId) If the DB is not actually set up to use an Identity but EF is configured for an Identity column (DatabaseGeneratedOption.Identity) the resulting insert statements will not include the ParkId column, resulting in a #null failure in the database.
I generally recommend being explicit with configuration rather than relying on EF's conventions for behaviour:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ParkId { get; set; }
If you expect the new records to be given a PK value automatically by the database then update the database schema to mark these PKs as Identity columns. If your schema is code-first and generating Migrations then there should be a way to apply a migration to update the PKs to identity columns. Otherwise simply make the change within SSMS.
If instead you want to provide PKs from your code, (such as part of data imports from other data sources) then you need to configure EF to not treat the PK as an Identity.
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ParkId { get; set; }

Dynamic Servicefabric Settings and Overrides

Is there a way to not tell the service about the settings at all and just provide them at the application level?
I am still unhappy with how servicefabric configuration seems to work.
Near as I can tell I have to specify in the service’s settings.xml all of the possible configuration values. Then I can override those in the application’s ApplicationParameters. Per documentation this looks like it holds true for environment variables also.
The complication that creates is that our configuration is used to hydrate options in many cases with arrays.
For example consider the json:
{
"AuthorizationOptions": {
"Policies": [
{
"Name": "User",
"Groups": [ "Domain Users" ]
}
]
}
}
There are 2 arrays; that are necessary and useful. To express this in the service fabric configuration it translates to:
<Section Name="AuthorizationOptions">
<Parameter Name="Policies:0:Name" Value="User"/>
<Parameter Name="Policies:0:Groups:0" Value="Domain Users"/>
</Section>
While the translation is not pleasant in comparison to the structured object it is completely usable.
However, If I don’t specify the section and parameters in the service, I can’t seem to override them in the application. So in this case I would have to define the exact number of policies and groups per policy in the service and the application could modify the policy name, or the group values, but not the number of policies total or number of groups total.
Is there a way to not tell the service about the settings at all and just provide them at the application level?
If not what alternatives exist to make the service reusable across applications that I may want to use to provide this type of dynamic configuration differently?
The last part of the puzzle that may assist in answering this question is I am using some pre-release code to translate the service fabric settings into Microsoft.Extensions.Configuration.IConfiguration. However, that is just taking the settings it finds; it isn't the cause of the override issue I am running into.
Example Service Settings.xml:
<?xml version="1.0" encoding="utf-8" ?>
<Settings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Section Name="AuthorizationOptions">
<!-- I should not have to provide these at the application level!
However, it fails to deploy if I don't. -->
<Parameter Name="Policies:0:Name" Value="User"/>
<Parameter Name="Policies:0:Groups:0" Value="Domain Users"/>
</Section>
</Settings>
Example Application ApplicationManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="ServiceFabric.ExampleType" ApplicationTypeVersion="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Parameters>
<Parameter Name="Service.Example_ASPNETCORE_ENVIRONMENT" DefaultValue="" />
<Parameter Name="Service.Example_InstanceCount" DefaultValue="-1" />
<Parameter Name="Service.Example_AuthorizationOptions_Policies_0_Name" DefaultValue="Users" />
<Parameter Name="Service.Example_AuthorizationOptions_Policies_0_Groups_0" DefaultValue="Domain Users" />
</Parameters>
<ServiceManifestImport>
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="Service.ExamplePkg" ServiceManifestVersion="1.0.0" />
<ConfigOverrides>
<ConfigOverride Name="Config">
<Settings>
<Section Name="AuthorizationOptions">
<Parameter Name="Policies:0:Name" Value="[Service.Example_AuthorizationOptions_Policies_0_Name]" />
<Parameter Name="Policies:0:Groups:0" Value="[Service.Example_AuthorizationOptions_Policies_0_Groups_0]" />
</Section>
</Settings>
</ConfigOverride>
</ConfigOverrides>
<EnvironmentOverrides CodePackageRef="code">
<EnvironmentVariable Name="ASPNETCORE_ENVIRONMENT" Value="[Service.Example_ASPNETCORE_ENVIRONMENT]" />
</EnvironmentOverrides>
</ServiceManifestImport>
<DefaultServices>
<Service Name="Service.Example" ServicePackageActivationMode="ExclusiveProcess">
<StatelessService ServiceTypeName="Service.ExampleType" InstanceCount="[Service.Example_InstanceCount]">
<SingletonPartition />
</StatelessService>
</Service>
</DefaultServices>
</ApplicationManifest>
Example Application ApplicationParameters (Local.1Node.xml):
<?xml version="1.0" encoding="utf-8"?>
<Application xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Name="fabric:/ServiceFabric.Example" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Parameters>
<Parameter Name="Service.Example_ASPNETCORE_ENVIRONMENT" Value="Development" />
<Parameter Name="Service.Example_InstanceCount" Value="-1" />
<Parameter Name="Service.Example_AuthorizationOptions_Policies_0_Name" Value="Users" />
<Parameter Name="Service.Example_AuthorizationOptions_Policies_0_Groups_0" Value="Domain Users" />
</Parameters>
</Application>
Example Application PublishProfiles (Local.1Node.xml):
<?xml version="1.0" encoding="utf-8"?>
<PublishProfile xmlns="http://schemas.microsoft.com/2015/05/fabrictools">
<ClusterConnectionParameters />
<ApplicationParameterFile Path="..\ApplicationParameters\Local.1Node.xml" />
</PublishProfile>
Should be unrelated, but example consumption of the settings:
internal sealed class Example : StatelessService
{
public Example(StatelessServiceContext context)
: base(context)
{ }
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new ServiceInstanceListener[]
{
new ServiceInstanceListener(serviceContext =>
new HttpSysCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
{
ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting HttpSys on {url}");
return new WebHostBuilder()
.UseHttpSys(options =>
{
options.Authentication.Schemes = AuthenticationSchemes.Negotiate; // Microsoft.AspNetCore.Server.HttpSys
options.Authentication.AllowAnonymous = false;
}).ConfigureServices(services => services.AddSingleton<StatelessServiceContext>(serviceContext))
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddServiceFabricConfiguration(FabricRuntime.GetActivationContext(), options => {
options.IncludePackageName=false;
});
})
.UseStartup<Startup>()
.UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
.UseUrls(url)
.Build();
}))
};
}
}
From that point forward everything is in the IConfiguration object as expected.
There are many ways to configure a service fabric application, and each approach will bring you to a different challenges.
SF team recommend the approach in the docs, because you can have a better version control of configurations, and makes harder to commit mistakes, as it is explicitly declared in a file, I've used a few different approaches because of limitations like yours, the follwoing approach might solve your problem:
Configure like the original approach, but with complex types stored as JSON values: it is the closest solution to the recommended design and you still can keep control of the configuration versions on source control.
It would be something like:
Settings.xml:
<?xml version="1.0" encoding="utf-8" ?>
<Settings xmlns... namespaces here...>
<Section Name="AuthorizationOptions">
<Parameter Name="Policies"/>
</Section>
</Settings>
ApplicationManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest ApplicationTypeName="ServiceFabric.ExampleType" ApplicationTypeVersion="1.0.0" xmlns:...namespaces....>
<Parameters>
<Parameter Name="Service.Example_ASPNETCORE_ENVIRONMENT" DefaultValue="" />
<Parameter Name="Service.Example_InstanceCount" DefaultValue="-1" />
<Parameter Name="Service.Example_AuthorizationOptions_Policies" DefaultValue="[]" />
</Parameters>
<ServiceManifestImport>
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="Service.ExamplePkg" ServiceManifestVersion="1.0.0" />
<ConfigOverrides>
<ConfigOverride Name="Config">
<Settings>
<Section Name="AuthorizationOptions">
<Parameter Name="Policies" Value="[Service.Example_AuthorizationOptions_Policies]" />
</Section>
</Settings>
</ConfigOverride>
</ConfigOverrides>
<EnvironmentOverrides CodePackageRef="code">
<EnvironmentVariable Name="ASPNETCORE_ENVIRONMENT" Value="[Service.Example_ASPNETCORE_ENVIRONMENT]" />
</EnvironmentOverrides>
</ServiceManifestImport>
<DefaultServices>
<Service Name="Service.Example" ServicePackageActivationMode="ExclusiveProcess">
<StatelessService ServiceTypeName="Service.ExampleType" InstanceCount="[Service.Example_InstanceCount]">
<SingletonPartition />
</StatelessService>
</Service>
</DefaultServices>
</ApplicationManifest>
ApplicationParameters.xml
<?xml version="1.0" encoding="utf-8"?>
<Application Name="fabric:/ServiceFabric.Example" xmlns:...namespaces....>
<Parameters>
<Parameter Name="Service.Example_ASPNETCORE_ENVIRONMENT" Value="Development" />
<Parameter Name="Service.Example_InstanceCount" Value="-1" />
<Parameter Name="Service.Example_AuthorizationOptions_Policies" Value="[{'Name': 'User','Groups': ['Domain Users']}, {'Name': 'Admin','Groups': ['Administrators']}]" />
</Parameters>
</Application>
In your service code:
public class Policy
{
public string Name { get; set; }
public string[] Groups { get; set; }
}
var settings = this.Context.CodePackageActivationContext.GetConfigurationPackageObject("Config").Settings;
var authOptions = settings.Sections["AuthorizationOptions"].Parameters["Policies"].Value;
var obj = JsonConvert.DeserializeObject<Policy[]>(authOptions);
You could go a level further and store the entire
AuthorizationOptions as a JSON, but like said previously, more
generic it become, easier will be to commit mistakes and harder to find
configuration issues.

Access Denied when deploying ASP.net 5

I'm trying to deploy an ASP.net 5 website to my local service fabric dev cluster but get an Access Denied exception on every deploy. I know that the problem is with the web service because when I remove it from the deployment my other service is deployed without any error
This exception looks like it is trying to delete a file, but which one and why wouldn't it have access?
6>. 'E:\Github\Flow.Server\Flow.Server.Fabric\Scripts\Deploy-FabricApplication.ps1' -ApplicationPackagePath 'E:\Github\Flow.Server\Flow.Server.Fabric\pkg\Debug' -PublishProfileFile 'E:\Github\Flow.Server\Flow.Server.Fabric\PublishProfiles\Local.xml' -DeployOnly:$true -UnregisterUnusedApplicationVersionsAfterUpgrade $false -OverrideUpgradeBehavior 'None' -OverwriteBehavior 'Always' -ErrorAction Stop
6>Message : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
6>Data : {}
6>InnerException :
6>TargetSite : Void RunInMTA(System.Action)
6>StackTrace : at System.Fabric.Interop.Utility.RunInMTA(Action action)
6> at System.Fabric.Common.FabricDirectory.Delete(String path, Boolean recursive, Boolean
6> deleteReadOnlyFiles)
6> at Microsoft.ServiceFabric.Powershell.ApplicationCmdletBase.TestApplicationPackage(String
6> applicationPackagePath, Hashtable applicationParameters, String imageStoreConnectionString)
6> at System.Management.Automation.CommandProcessor.ProcessRecord()
6>HelpLink :
6>Source : System.Fabric
6>HResult : -2147024891
Here is my ApplicationManifest
<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="Flow.Server.FabricType" ApplicationTypeVersion="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Parameters>
<Parameter Name="Silo_InstanceCount" DefaultValue="-1" />
</Parameters>
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="Flow.Server.Fabric.WebApi" ServiceManifestVersion="1.0.0" />
</ServiceManifestImport>
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="Flow.Server.Fabric.SiloPkg" ServiceManifestVersion="1.0.0" />
<ConfigOverrides />
</ServiceManifestImport>
<DefaultServices>
<Service Name="Flow.Server.Fabric.WebApiService">
<StatelessService ServiceTypeName="Flow.Server.Fabric.WebApiType">
<SingletonPartition />
</StatelessService>
</Service>
<Service Name="Flow.Server.Fabric.Silo">
<StatelessService ServiceTypeName="Flow.Server.Fabric.SiloType" InstanceCount="[Silo_InstanceCount]">
<SingletonPartition />
</StatelessService>
</Service>
</DefaultServices>
</ApplicationManifest>
And here is the ServiceManifest
<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Name="Flow.Server.Fabric.WebApi" Version="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<ServiceTypes>
<StatelessServiceType ServiceTypeName="Flow.Server.Fabric.WebApiType">
<Extensions>
<Extension Name="__GeneratedServiceType__">
<GeneratedNames xmlns="http://schemas.microsoft.com/2015/03/fabact-no-schema">
<DefaultService Name="Flow.Server.Fabric.WebApiService" />
<ServiceEndpoint Name="Flow.Server.Fabric.WebApiTypeEndpoint" />
</GeneratedNames>
</Extension>
</Extensions>
</StatelessServiceType>
</ServiceTypes>
<CodePackage Name="C" Version="1.0.0">
<EntryPoint>
<ExeHost>
<Program>approot\runtimes\dnx-clr-win-x64.1.0.0-rc1-update1\bin\dnx.exe</Program>
<Arguments>--appbase approot\src\Flow.Server.Fabric.WebApi Microsoft.Dnx.ApplicationHost Microsoft.ServiceFabric.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener</Arguments>
<WorkingFolder>CodePackage</WorkingFolder>
<ConsoleRedirection FileRetentionCount="5" FileMaxSizeInKb="2048" />
</ExeHost>
</EntryPoint>
</CodePackage>
<Resources>
<Endpoints>
<Endpoint Name="Flow.Server.Fabric.WebApiTypeEndpoint" Protocol="http" Type="Input" />
</Endpoints>
</Resources>
</ServiceManifest>

GWT remote logging going to System.out instead of log file

I have setup gwt remote logging based on the gwt documentation, however my logs are going to System.out instead of being written to a log file.
My gwt module looks like:
<module rename-to='ezdappserver'>
<inherits name="com.google.gwt.logging.Logging"/>
<set-property name="gwt.logging.simpleRemoteHandler" value="ENABLED" />
<set-property name="gwt.logging.logLevel" value="FINEST"/>
<set-property name="gwt.logging.enabled" value="TRUE"/>
<set-property name="gwt.logging.consoleHandler" value="ENABLED" />
<set-property name="gwt.logging.popupHandler" value="DISABLED" />
</module>
My servlet definition is setup like:
<servlet>
<servlet-name>remoteLogging</servlet-name>
<servlet-class>com.google.gwt.logging.server.RemoteLoggingServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>remoteLogging</servlet-name>
<url-pattern>/ezdappserver/remote_logging</url-pattern>
</servlet-mapping>
When an error is logged I see output in my console like so:
Mar 26, 2014 2:10:36 PM com.google.gwt.logging.server.RemoteLoggingServiceUtil logOnServer
SEVERE: Exception caught: (NotFoundError)
....Rest of error....
I was expecting this output to be written to a log file somewhere in my war. Also, I would really like to be able to specify where this file is located, however I haven't been able to find any documentation on that either.
Any help would be much appreciated.
NOTE: I am not running this through dev mode, this is with compiled code.
Thanks!
Try below options also in gwt.xml based on your requirement:
<!-- This handler sends log messages to the server, where they will be logged using the server side logging mechanism. -->
<set-property name="gwt.logging.simpleRemoteHandler" value="ENABLED" />
<!-- Logs by calling method GWT.log. These messages can only be seen in Development Mode in the DevMode window. -->
<set-property name="gwt.logging.developmentModeHandler" value="ENABLED" />
<!-- These messages can only be seen in Development Mode in the DevMode window. -->
<set-property name="gwt.logging.systemHandler" value="ENABLED" />
<!-- Logs to the popup which resides in the upper left hand corner of application when this handler is enabled. -->
<set-property name="gwt.logging.popupHandler" value="DISABLED" />
<!-- Logs to the javascript console, which is used by Firebug Lite (for IE), Safari and Chrome. -->
<set-property name="gwt.logging.consoleHandler" value="DISABLED"/>
<!-- Logs to the firebug console. -->
<set-property name="gwt.logging.firebugHandler" value="DISABLED" />
If above configuration are still not working for you then try below code along with above configuration.
Add log4j.xml file to define the log file location with log level
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="DT=> %d [%.4t] %-5p %c{1} - %m%n" />
</layout>
</appender>
<appender name="SERVER_FILE_LOG" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="${jboss.server.log.dir}/logs/DataTools_Server.log" />
<param name="Append" value="true" />
<param name="MaxFileSize" value="5MB" />
<param name="MaxBackupIndex" value="10" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d [%.4t] %-5p [%c] %m%n" />
</layout>
</appender>
<appender name="CLIENT_FILE_LOG" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="${jboss.server.log.dir}/logs/DataTools_Client.log" />
<param name="Append" value="true" />
<param name="MaxFileSize" value="5MB" />
<param name="MaxBackupIndex" value="10" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d [%.4t] %-5p %m%n" />
</layout>
</appender>
<category name="com.x.y.server">
<priority value="DEBUG" />
<appender-ref ref="SERVER_FILE_LOG" />
<appender-ref ref="STDOUT" />
</category>
<category name="gwtRemoteLogging">
<priority value="ERROR" />
<appender-ref ref="CLIENT_FILE_LOG" />
</category>
<root>
<priority value ="ERROR" />
<appender-ref ref="SERVER_FILE_LOG" />
</root>
</log4j:configuration>
Define you own logging servlet by implementing RemoteLoggingService
import java.util.logging.Level;
import java.util.logging.LogRecord;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import com.google.gwt.logging.server.StackTraceDeobfuscator;
import com.google.gwt.logging.shared.RemoteLoggingService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import org.apache.log4j.Logger;
/**
* The Class GwtRemoteLogging.
*/
#SuppressWarnings("serial")
public class GwtRemoteLogging extends RemoteServiceServlet implements RemoteLoggingService {
/** The Constant logger. */
private StackTraceDeobfuscator deobfuscator = null;
private final static Logger logger = Logger.getLogger("gwtRemoteLogging");
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
/**
* Logs a Log Record which has been serialized using GWT RPC on the server.
*
* #return either an error message, or null if logging is successful.
*/
public final String logOnServer(LogRecord lr) {
try {
if (lr.getLevel().equals(Level.SEVERE)) {
logger.error(lr.getMessage(),lr.getThrown());
} else if (lr.getLevel().equals(Level.INFO)) {
logger.info(lr.getMessage(),lr.getThrown());
} else if (lr.getLevel().equals(Level.WARNING)) {
logger.warn(lr.getMessage(),lr.getThrown());
} else if (lr.getLevel().equals(Level.FINE)) {
logger.debug(lr.getMessage(),lr.getThrown());
} else {
logger.trace(lr.getMessage(),lr.getThrown());
}
} catch (Exception e) {
logger.error("Remote logging failed", e);
return "Remote logging failed, check stack trace for details.";
}
return null;
}
/**
* By default, this service does not do any deobfuscation. In order to do server side
* deobfuscation, you must copy the symbolMaps files to a directory visible to the server and
* set the directory using this method.
*
* #param symbolMapsDir
*/
public void setSymbolMapsDirectory(String symbolMapsDir) {
if (deobfuscator == null) {
deobfuscator = new StackTraceDeobfuscator(symbolMapsDir);
} else {
deobfuscator.setSymbolMapsDirectory(symbolMapsDir);
}
}
}
web.xml
<servlet>
<servlet-name>remoteLogServlet</servlet-name>
<servlet-class>com.x.y.server.servlet.GwtRemoteLogging</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>remoteLogServlet</servlet-name>
<url-pattern>/ezdappserver/remote_logging</url-pattern>
</servlet-mapping>
The RemoteServiceServlet uses java.util.logging to log, and by default it logs to the console (System.err, not System.out BTW).
If you want to log to a file, then you have to configure java.util.logging; either editing your global lib/logging.properties (not recommended), using your own config file that you pass to the JVM using the java.util.logging.config.file system property, or programmatically.
Depending on your servlet container, it can be configured by different means. For instance, Tomcat will read a logging.properties file in your WEB-INF/classes: http://tomcat.apache.org/tomcat-7.0-doc/logging.html#Using_java.util.logging_(default)

I get an error when using redirectAction with struts2 and portlets inside jboss portal

I have the following struts.xml:
<struts>
<package name="default" namespace="/view" extends="struts-portlet-default">
<action name="index" class="com.gigi.LoginAction">
<result type="redirectAction">
<param name="actionName">showAlerts</param>
<param name="namespace">/view</param>
<param name="portletMode">view</param>
</result>
<result name="error">/includes/error.jsp</result>
</action>
<action name="showAlerts" class="com.gigi.AlertsAction">
<result>/jsp/view/Alerts.jsp</result>
</action>
</package>
<package name="edit" namespace="/edit" extends="struts-portlet-default">
<action name="index" class="com.gigi.UpdateNameAction">
<result type="redirectAction">
<param name="actionName">index</param>
<param name="portletMode">view</param>
</result>
<result name="input">/jsp/edit/index.jsp</result>
</action>
</package>
</struts>
and LoginAction has the following execute method:
public String execute() throws Exception {
boolean loggedIn = checkLogin();
System.out.println("LoggedIn = " + loggedIn);
if (loggedIn) {
return SUCCESS;
}
return ERROR;
}
I am trying a redirect from LoginAction to AlertsAction. Every time I open the portlet in jboss portal 2.7.1, I get the following error:
The requested resource (/portlet/view/showAlerts) is not available
Can anyone tell me what I am doing wrong?
I tried writing the redirect in different ways, but the result is the same...
Thanks.
Where exactly is Alerts.jsp? Is it in /jsp or /WEB-INF/jsp? Can you log something out of the execute() method of AlertsAction?