Serilog in Blazor server .Net6 to split error messages to a different file - serilog

In serilog, I need to split the information in two files. i.e one file should contain the Information and the other should contain the error. with the below code and configuration, the information and the errors both displays in both files, instead of filtering out.
Note: I am trying this in .Net6 in Serverside Blazor. Please help us.
Thanks in Advance
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Expressions" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"Enrich": [
"FromLogContext",
"WithMachineName"
],
"WriteTo": [
{
"Name": "Console"
},
{
"Name": "File",
"Args": {
"path": "Logs/ex_.log",
"outputTemplate": "{Timestamp:o} [{Level:u3}] ({SourceContext}) {Message:lj}{NewLine}{Exception}",
"rollingInterval": "Day",
"retainedFileCountLimit": 7
}
},
{
"Name": "Logger",
"Args": {
"configureLogger": {
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "(#Level = 'Information' )"
}
}
],
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "Logs/ERROR_.log",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
"rollingInterval": "Day",
"retainedFileCountLimit": 7
}
}
]
}
}
}
]
}
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateBootstrapLogger();
WebApplicationBuilder builder;
try
{
Log.Information("Application starting .....");
builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog((ctx, lc) => lc
.WriteTo.Console()
.ReadFrom.Configuration(ctx.Configuration));
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddTelerikBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSerilogRequestLogging();
app.UseRouting();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
}
catch (Exception ex)
{
Log.Fatal("Application even failed to start....");
}

You need to make sure the following NuGet packages are installed. You can find this working example code on GitHub here
Serilog,
Serilog.AspNetCore
Serilog.Settings.Configuration
Serilog.Sinks.File, Serilog.Sinks.* (whatever sink type you are
using, relevant package)
Serilog.Expressions,
Serilog.Enrichers.*(this package is an optional choice) if you want to use enrichers.
I am using Blazor Serverside with .Net6 example here.
Program.cs
using Serilog;
var builder = WebApplication.CreateBuilder(args);
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.WriteTo.Console()
.WriteTo.Logger(lc => lc
.Filter.ByIncludingOnly(" #l = 'Debug' or #l = 'Information' or #l = 'Warning'")
.WriteTo.File("Logs/Log-Information-{Date}.log", rollingInterval: RollingInterval.Day))
.WriteTo.Logger(lc => lc
.Filter.ByIncludingOnly(" #l = 'Error' or #l = 'Fatal'")
.WriteTo.File("Logs/Log-Error-{Date}.log", rollingInterval: RollingInterval.Day))
.CreateLogger();
Log.Information("Starting up");
Serilog.Log.Information("Starting application");
Serilog.Log.Error("Error");
Serilog.Log.Fatal("Fatal");
Serilog.Log.Debug("Debug");
// Add services to the container.
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
builder.Services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy.
options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
Appsettings.json file:
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Warning",
"Microsoft.Extensions.DependencyInjection": "Warning",
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "{Timestamp:HH:mm:ss} [{Level}] {SourceContext}{NewLine}{Message}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"Path": "./logs/log.txt",
"IncludeScopes": true,
"TimestampFormat": "yyyy-MM-dd HH:mm:ss",
"RollingInterval": "Day"
}
},
{
"Name": "Seq",
"Args": { "serverUrl": "http://localhost:5341"}
}
]
}
The above code snippet will generate two different log files under the "./Logs/" path, per the below screenshot.
Inside the files:
Note: I have added "#using Serilog" into _Imports.razor as well.
My project package references:
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.Negotiate" Version="6.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.5" />
<PackageReference Include="Serilog" Version="2.11.0" />
<PackageReference Include="Serilog.AspNetCore" Version="5.0.0" />
<PackageReference Include="Serilog.Expressions" Version="3.3.0" />
<PackageReference Include="Serilog.Sinks.Seq" Version="5.1.1" />
<PackageReference Include="Serilog.Enrichers.AspNetCore.HttpContext" Version="1.0.1" />
<PackageReference Include="Serilog.Enrichers.AssemblyName" Version="1.0.9" />
<PackageReference Include="Serilog.Enrichers.Context" Version="4.2.0" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.0" />
<PackageReference Include="Serilog.Enrichers.Memory" Version="1.0.4" />
<PackageReference Include="Serilog.Enrichers.Process" Version="2.0.2" />
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0" />
<PackageReference Include="Serilog.Sinks.MSSqlServer" Version="5.7.0" />
</ItemGroup>

Related

I get 404 error after configuring AspNetCoreRateLimit library in my code

When I remove the rate related codes, the app works fine. If I write these codes, I get 404 error.
If await webHost.RunAsync(); , await IpPolicy.SeedAsync(); If I remove the await keyword in the , I get the error localhost refused to connect. How can I solve this problem?
Program.cs
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddDbContext(builder);
builder.Services.AddControllersWithViews();
builder.Services.AddValidatorsFromAssemblyContaining<Program>();
builder.Services.AddFluentValidationAutoValidation().AddFluentValidationClientsideAdapters();
builder.Services.AddMapster();
builder.Services.AddIdentity();
builder.Services.AddCookieConfiguration();
builder.Services.AddOptions();
builder.Services.AddMemoryCache();
builder.Services.Configure<IpRateLimitOptions>(builder.Configuration.GetSection("IpRateLimiting"));
builder.Services.Configure<IpRateLimitPolicies>(builder.Configuration.GetSection("IpRateLimitPolicies"));
builder.Services.AddInMemoryRateLimiting();
builder.Services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
builder.Services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
builder.Services.AddHttpContextAccessor();
builder.Services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
using IHost webHost = builder.Build();
using (var scope = webHost.Services.CreateScope())
{
IIpPolicyStore IpPolicy = scope.ServiceProvider.GetRequiredService<IIpPolicyStore>();
await IpPolicy.SeedAsync();
}
await webHost.RunAsync();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseIpRateLimiting();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
RoleSeed.Seed(app);
app.Run();
appsettings.json
{
"ConnectionStrings": { "SqlCon": "" },
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
"HttpStatusCode": 429,
//"IpWhitelist": [ "127.0.0.12" ],
//"EndpointWhitelist": [ "*:/api/customers" ],
"GeneralRules": [
{
"Endpoint": "*",
"Period": "10 s",
"Limit": 20
}
]
},
"IpRateLimitPolicies": {
"IpRules": [
{
"Ip": "*",
"Rules": [
{
"Endpoint": "*",
"Period": "10m",
"Limit": 150
}
]
}
]
}
}
i changed the service order and then i got this error how can i solve it?

How to search for all nodes in a sap.m.Tree?

I'm currently working at a MasterDetail application for my company, which provides expandable categorys represented as nodes.
The binding of the nodes and it's child nodes with a navigation property isn't a problem. However, if I want to search for a certain group node in the search field above, it only filters between the four highest nodes. It can search for the nodes on the first level, but it isn't able to find nodes if they're below the first level.
Binding of the tree:
<Tree
selectionChange="onSelectionChange"
id="list"
noDataText="{masterView>/noDataText}"
busyIndicatorDelay="{masterView>/delay}"
items="{path: '/GroupNodes',
parameters : {
expand: 'ChildGroupNodes',
navigation: {
'GroupNodes': 'ChildGroupNodes'
}
}
}">
<StandardTreeItem
title="{Stext}"
type="Navigation"
press="onSelectionChange"/>
</Tree>
onSearch:
onSearch: function(oEvent) {
if (oEvent.getParameters().refreshButtonPressed) {
this.onRefresh();
return;
}
var sQuery = oEvent.getParameter("query");
if (sQuery) {
this._oListFilterState.aSearch = [new Filter("Stext", FilterOperator.Contains, sQuery)];
} else {
this._oListFilterState.aSearch = [];
}
this._applyFilterSearch();
},
_applyFilterSearch:
_applyFilterSearch: function() {
var aFilters = this._oListFilterState.aSearch.concat(this._oListFilterState.aFilter),
oViewModel = this.getModel();
this._oList.getBinding("items").filter(aFilters, "Application");
if (aFilters.length !== 0) {
oViewModel.setProperty("/noDataText", this.getResourceBundle().getText("masterListNoDataWithFilterOrSearchText"));
} else if (this._oListFilterState.aSearch.length > 0) {
oViewModel.setProperty("/noDataText", this.getResourceBundle().getText("masterListNoDataText"));
}
},
Filterstate in the onInit() function:
this._oListFilterState = {
aFilter: [],
aSearch: []
};
Metadata:
<EntityType Name="GroupNode" sap:content-version="1">
<Key>
<PropertyRef Name="Grpid"/>
</Key>
<Property Name="Grpid" Type="Edm.String" Nullable="false" MaxLength="8" sap:unicode="false" sap:label="Id Trainingsgruppe" sap:creatable="false" sap:updatable="false" sap:filterable="false"/>
<Property Name="Short" Type="Edm.String" MaxLength="12" sap:unicode="false" sap:label="Kürzel Trainingsgruppe" sap:creatable="false" sap:updatable="false" sap:sortable="false" sap:filterable="false"/>
<Property Name="Stext" Type="Edm.String" MaxLength="40" sap:unicode="false" sap:label="Bezeichnung Trainingsgruppe" sap:creatable="false" sap:updatable="false" sap:filterable="false"/>
<Property Name="Begda" Type="Edm.DateTime" Precision="0" sap:unicode="false" sap:label="Beginndatum" sap:creatable="false" sap:updatable="false" sap:sortable="false" sap:filterable="false"/>
<Property Name="Endda" Type="Edm.DateTime" Precision="0" sap:unicode="false" sap:label="Endedatum" sap:creatable="false" sap:updatable="false" sap:sortable="false" sap:filterable="false"/>
<Property Name="Level" Type="Edm.Int32" sap:unicode="false" sap:label="Level" sap:creatable="false" sap:updatable="false" sap:sortable="false" sap:filterable="false"/>
<Property Name="Parentid" Type="Edm.String" Nullable="false" MaxLength="8" sap:unicode="false" sap:label="ParentId" sap:creatable="false" sap:updatable="false" sap:filterable="false"/>
<NavigationProperty Name="ChildGroupNodes" Relationship="Z_HR_LSO_WORKCENTER_SRV.GroupNodeToParent" FromRole="FromRole_GroupNodeToParent" ToRole="ToRole_GroupNodeToParent"/>
<NavigationProperty Name="GroupToTrainingType" Relationship="Z_HR_LSO_WORKCENTER_SRV.GroupToTrainingType" FromRole="FromRole_GroupToTrainingType" ToRole="ToRole_GroupToTrainingType"/>
</EntityType>
We're working with OData V2, so there's no possibility to implement an FilterContains.All filter.
Is it even possible to filter through the child nodes of a sap.m.Tree in the front-end?
First of all, building the tree hierarchy via navigation is deprecated since 1.44. Instead, SAP recommends to leverage metadata annotations:
The use of navigation properties to build up the hierarchy structure is deprecated and it is recommended to use the hierarchy annotations [...].
Once the migration to the annotation approach is done, filter either client-side or server-side.
Client-side
The operationMode of the ODataTreeBinding (or the defaultOperationMode of the v2.ODataModel) needs to be "Client".
When calling .filter, the FilterType as the 2nd argument needs to be "Control".
Here is a working example: https://embed.plnkr.co/moTGOT
Server-side
For server-side filtering, only the FilterType "Application" and the operationMode: "Server" are supported. In that case, the server needs to respond to the $filter request with a ready-made tree structure. The same applies to paging requests for sibling and child nodes.
Limitations
suspended: true in the binding info is not yet supported (Issue #3161).
The above content applies to OData V2 only.
V4 ODataModel doesn't support tree binding at all yet (Issue #2728).
I think this may have something to do with the way you're binding the items, because I am able to filter on child nodes just fine in my example using your JS.
Check that this._oList.getItems() has all the items in it before you do the filter.
I'll post my code, so you can rebuild my project and get a feel for how it works. Let me know if you have more questions.
Page.view.xml
<mvc:View
controllerName="sap.m.sample.Tree.Page"
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m">
<SearchField value="{json>/search}" search="onSearch"/>
<Tree
id="Tree"
items="{path: '/'}">
<StandardTreeItem title="{text}"/>
</Tree>
</mvc:View>
Page.controller.js
sap.ui.define(['sap/ui/core/mvc/Controller', 'sap/ui/model/json/JSONModel', 'sap/ui/model/Filter', 'sap/ui/model/FilterOperator'],
function(Controller, JSONModel, Filter, FilterOperator) {
"use strict";
var PageController = Controller.extend("sap.m.sample.Tree.Page", {
onInit: function(evt) {
// set explored app's demo model on this sample
var oModel = new JSONModel(jQuery.sap.getModulePath("sap.m.sample.Tree", "/Tree.json"));
this.getView().setModel(oModel);
var oJSONModel = new JSONModel();
this.getView().setModel("json", oJSONModel);
this._oList = this.byId("Tree");
this._oListFilterState = {
aFilter: [],
aSearch: []
};
},
onSearch: function(oEvent) {
if (oEvent.getParameters().refreshButtonPressed) {
this.onRefresh();
return;
}
var sQuery = oEvent.getParameter("query");
if (sQuery) {
this._oListFilterState.aSearch = [new Filter("text", FilterOperator.Contains, sQuery)];
} else {
this._oListFilterState.aSearch = [];
}
this._applyFilterSearch();
},
_applyFilterSearch: function() {
var aFilters = this._oListFilterState.aSearch.concat(this._oListFilterState.aFilter);
//oViewModel = this.getModel();
this._oList.getBinding("items").filter(aFilters, "Application");
// if (aFilters.length !== 0) {
// oViewModel.setProperty("/noDataText", this.getResourceBundle().getText("masterListNoDataWithFilterOrSearchText"));
// } else if (this._oListFilterState.aSearch.length > 0) {
// oViewModel.setProperty("/noDataText", this.getResourceBundle().getText("masterListNoDataText"));
// }
}
});
return PageController;
});
Tree.json
[
{
"text": "Node1",
"ref": "sap-icon://attachment-audio",
"nodes":
[
{
"text": "Node1-1",
"ref": "sap-icon://attachment-e-pub",
"nodes":[
{
"text": "Node1-1-1",
"ref": "sap-icon://attachment-html"
},
{
"text": "Node1-1-2",
"ref": "sap-icon://attachment-photo",
"nodes":[
{
"text": "Node1-1-2-1",
"ref": "sap-icon://attachment-text-file",
"nodes":[
{
"text": "Node1-1-2-1-1",
"ref": "sap-icon://attachment-video"
},
{
"text": "Node1-1-2-1-2",
"ref": "sap-icon://attachment-zip-file"
},
{
"text": "Node1-1-2-1-3",
"ref": "sap-icon://course-program"
}
]
}
]
}
]
},
{
"text": "Node1-2",
"ref": "sap-icon://create"
}
]
},
{
"text": "Node2",
"ref": "sap-icon://customer-financial-fact-sheet"
}
]
That's all you should need, but just incase you need these as well...
index.html
<!DOCTYPE HTML>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<title>Tree - Basic</title>
<script id="sap-ui-bootstrap"
src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.m"
data-sap-ui-theme="sap_belize"
data-sap-ui-xx-bindingSyntax="complex"
data-sap-ui-preload="async"
data-sap-ui-compatVersion="edge"
data-sap-ui-resourceroots='{"sap.m.sample.Tree": "./", "sap.ui.demo.mock": "mockdata"}'>
</script>
<!-- Application launch configuration -->
<script>
sap.ui.getCore().attachInit(function() {
new sap.m.App ({
pages: [
new sap.m.Page({
title: "Tree - Basic",
enableScrolling : true,
content: [ new sap.ui.core.ComponentContainer({
name : "sap.m.sample.Tree"
})]
})
]
}).placeAt("content");
});
</script>
</head>
<!-- UI Content -->
<body class="sapUiBody" id="content" role="application">
</body>
Component.js
sap.ui.define(['sap/ui/core/UIComponent'],
function(UIComponent) {
"use strict";
var Component = UIComponent.extend("sap.m.sample.Tree.Component", {
metadata : {
rootView : "sap.m.sample.Tree.Page",
dependencies : {
libs : [
"sap.m",
"sap.ui.layout"
]
},
config : {
sample : {
files : [
"Page.view.xml",
"Page.controller.js",
"Tree.json"
]
}
}
}
});
return Component;
});
Not sure if you managed to solve your problem, but I actually did this exact thing a few months ago.
In your controller, put the following function:
onSearch: function(oEvent) {
var searchVal = oEvent.getParameter("newValue");
var treeFilter = new sap.ui.model.Filter("Text", sap.ui.model.FilterOperator.Contains, searchVal);
var oBinding = this.getView().byId("tree").mBindingInfos.rows.binding;
oBinding.filter(treeFilter, FilterType.Application);
oBinding.expandToLevel(3);
},
And this should work straight away. Whatever you enter in the search box, it will populate the tree (up to 3 levels, but this can be changed) with your filter.
The onSearch function is of course executed on the livechange of the search field.

Serilog Exceptionless Sink in .NET Core 1.1

How can the Serilog Exceptionless Sink be used with .NET Core 1.1?
The Serilog.Sinks.Exceptionless README isn't clear and doesn't work for .NET Core 1.1 where I have put the configuration in the appsettings.json file.
{
"Serilog": {
"Using": ["Serilog.Sinks.Literate"],
"MinimumLevel": ["Debug"],
"WriteTo": [{
"Name": "LiterateConsole"
}],
"Enrich": ["FromLogContext"],
"Properties": {
"Application": "MyAppServer"
}
}
}
Program.cs
public class Program
{
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(config)
.CreateLogger();
}
}
I obviously need to set up the API key somewhere, too.
Can anyone provide a clear description of how this can be configured, please?
In JSON you can add additional sinks to the "WriteTo" list and add arguments like apiKey in the "Args" block:
{
"Serilog": {
"Using": ["Serilog.Sinks.Literate"],
"MinimumLevel": ["Debug"],
"WriteTo": [{
"Name": "LiterateConsole"
}, {
"Name": "Exceptionless",
"Args": { apiKey: "12345" }
}],
"Enrich": ["FromLogContext"],
"Properties": {
"Application": "MyAppServer"
}
}
}
I think it's
Log.Logger = new LoggerConfiguration()
.WriteTo.Exceptionless(
apiKey: "yourApiKey",
additionalOperation: b => b.AddTags("ASP.NET Core Example Logger"))
.CreateLogger();

How to customise Shell container in SAPUI5

I've a shell container and on big screens i want to utilize full with of screen. i want to cover full area. how i can customize it.
I assume you are using XML for your views. Add the following attribute appWidthLimited="false" to the Shell tag.
When working with a manifest.json file and the UI5-framework instantiates a shell control, do the following (appWidthLimited="false" cannot be used as you don't have a xml containing a shell 'tag').
manifest.json
...
"sap.ui5": {
"config": {
"fullWidth": true
},
...
...
As per latest documentation, I referred to 1.48.X, and it's not there in the sap.ui5 anymore:
"sap.ui": {
"technology": "UI5",
"icons": {
"icon": "sap-icon://add-contact",
"favIcon": "icon/F1373_Approve_Purchase_Orders.ico",
"phone": "icon/launchicon/57_iPhone_Desktop_Launch.png",
"phone#2": "icon/launchicon/114_iPhone-Retina_Web_Clip.png",
"tablet": "icon/launchicon/72_iPad_Desktop_Launch.png",
"tablet#2": "icon/launchicon/144_iPad_Retina_Web_Clip.png"
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": false
},
"supportedThemes": [
"sap_hcb"
],
"fullWidth": true
},
For more info: https://openui5.hana.ondemand.com/#/topic/be0cf40f61184b358b5faedaec98b2da
Also, if you are using sap.m.Shell, then the above will not help.
For that you need to set the property appWidthLimited: false:
<script>
sap.ui.getCore().attachInit(function () {
new sap.m.Shell({
app: new sap.ui.core.ComponentContainer({
height: "100%",
name: "APPNAME"
}),
appWidthLimited: false
})
.placeAt("content");
});
</script>
It can be done either statically, via XML-template:
<mvc:View controllerName="letterboxing.widescreen.controller.index" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m">
<Shell id="shell" appWidthLimited="false">
<App id="app">
<pages>
<Page id="page" title="{i18n>title}">
<content></content>
</Page>
</pages>
</App>
</Shell>
</mvc:View>
Or dynamically via JS-controller, which will set appWidthLimited:false to the sap.m.Shell.

SAPUI5 Two oData Datasources within manifest / descriptor

i'm using SAPUI5 Version gt 1.30 and I try to define the automatic model instantiation of two external services within the manifest.
My first question is, are more than one odata services allowed? Sorry, but i'cant find it out by the documentation.
The default datasource ("") works. But the second datasource ("HLA") not.
If more than once are allowed, please could somebody look for the right definition.
"sap.app":
"dataSources": {
"mainService": {
"uri": "path.xsodata/",
"type": "OData",
"settings": {
"odataVersion": "2.0",
"localUri": "localService/metadata.xml"
}
}
"secondService": {
"uri": "/path.......xsodata/",
"type": "OData",
"settings": {
"annotations": [],
"odataVersion": "2.0",
"localUri": ""
}
}
},
"sap.ui5":
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "....i18n.i18n"
}
},
"": {
"dataSource": "mainService",
"settings": {
"metadataUrlParams": {
"sap-documentation": "heading"
}
}
},
"HLA": {
"dataSource": "secondService",
"settings": {
"metadataUrlParams": {
"sap-documentation": "heading"
}
}
}
}
Thanks a lot!
Not sure if you have solved your problem, but I encountered the same problem today too. And I realise you need to use different notations when binding those two data sources to a control. I'm using XML view btw.
For the default "" model:
<Table id="table" inset="true" items="{/}" >
<columns>
<Column>
<Text text="ID"/>
</Column>
<Column>
<Text text="Name"/>
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<Text text="{id}"/>
<Text text="{name}"/>
</cells>
</ColumnListItem>
</items>
</Table>
For the second model named "Users":
<Table id="userTable" inset="true" items="{Users>/}">
<columns>
<Column>
<Text text="ID"/>
</Column>
<Column>
<Text text="Last Name"/>
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<Text text="{Users>empNumber}"/>
<Text text="{Users>lastName}"/>
</cells>
</ColumnListItem>
</items>
</Table>
It works for me :)
Of course you can have more than one data source, but it is recommended by the fiori guidelines to only use one.
Do you want your address to look like this path.......xsodata/ ?
Also I think you should remove the localUri from the second data source.
Because if there is no metadata document this might throw an arror.
"secondService": {
"uri": "/proxy/service.xsodata",
"type": "oData",
"settings": {
"odataVersion": "2.0"
}
}
What is the output of the debugger? Do you get an error?
Also your oData model should have a type.
"HLA": {
"dataSource": "secondService",
"type": "sap.ui.model.odata.v2.ODataModel"
}

Resources