Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.80/5: Рейтинг темы: голосов - 5, средняя оценка - 4.80
3 / 3 / 0
Регистрация: 23.12.2016
Сообщений: 254

DI и зависимость в виде строки

17.02.2025, 08:45. Показов 2729. Ответов 24

Студворк — интернет-сервис помощи студентам
Здравствуйте.
Использую DI от Microsoft : Microsoft.Extensions.DependencyInjection
Появилась необходимость для контекста передать строку подключения к базе, как зависимость. строка находит в конфиг файле и лежит на сервере, в этом файле не только строка подключения к базе, но и другие настройки (соответственно и есть класс для десериализации этих настроек).
Не хотелось бы в контекст передавать все настройки, хочется только строку подключения.

У Microsoft увидел такую библиотеку Microsoft.Extensions.Options и использование в DI AddOptions. но как я понимаю для этого мне придется делать отдельный класс для строки подключения, регистрировать его как параметр и в контексте принимать IOptions<ConnectionString>.
Может быть я что-то не так понял, но можно ли как то при помощи Options зарегистрировать в DI именно строку из объекта настроек и передать в нужный сервис в таком виде чтобы принималась string connectionString? или может быть каким-то другим способом это можно сделать?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
17.02.2025, 08:45
Ответы с готовыми решениями:

Программирование с использованием строк (обычный вариант и с использованием 3 видов строк
используя символьный тип char(символ), который соответствует классу System.Char, для организации строки – массив символов типа char,...

Как проверить, что строка имеет правильный вид?
Кароче просто есть строка с ip адресом например 192.168.0.100 либо другая. Как проверить, что строка записана правильно, т.е. не ввели...

DataGrid и несколько видов(шаблонов) строк
Есть надобность в DataGrid сделать так: идут данные, надо вставить данные в другом(шаблоне строки) виде. Скажем: данные идут с текстом,...

24
 Аватар для Andrey-MSK
3313 / 2200 / 387
Регистрация: 14.08.2018
Сообщений: 7,404
Записей в блоге: 4
17.02.2025, 09:16
IIIIIIIIIgor, А кто мешает получить файл конфигурации в сервис?
C#
1
2
3
4
5
6
7
8
private static IConfiguration GetConfiguration()
{
    IConfigurationBuilder builder = new ConfigurationBuilder()
        .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
        .AddJsonFile("appsettings.json");
 
    return builder.Build();
}
И потом использовать нужные значения где нужно
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using DALibrary.DataAccess;
using DALibrary.Interfaces;
 
using Microsoft.Extensions.Configuration;
 
namespace DALibrary
{
    public class MainDA : IMainDA
    {
        private readonly IConfiguration _configuration;
        private readonly string _connectionString;
 
        public MainDA(IConfiguration configuration)
        {
            _configuration = configuration;
 
#if DEBUG
            _connectionString = _configuration.GetConnectionString("SQLConnectDebug");
#elif RELEASE || RELEASEALFA
            _connectionString = _configuration.GetConnectionString("SQLConnect");
#endif
        }
    }
}
1
 Аватар для Calabonga
14 / 13 / 1
Регистрация: 13.02.2025
Сообщений: 33
17.02.2025, 10:57
Цитата Сообщение от IIIIIIIIIgor Посмотреть сообщение
но можно ли как то при помощи Options зарегистрировать в DI именно строку из объекта настроек и передать в нужный сервис в таком виде чтобы принималась string connectionString? или может быть каким-то другим способом это можно сделать?
Нет, только строку использовать не получиться, потому что constrain на TOptions как раз class (https://learn.microsoft.com/en... net-9.0-pp):

C#
1
public interface IOptions<out TOptions> where TOptions : class
2
3 / 3 / 0
Регистрация: 23.12.2016
Сообщений: 254
17.02.2025, 11:14  [ТС]
Цитата Сообщение от Andrey-MSK Посмотреть сообщение
А кто мешает получить файл конфигурации в сервис?
тогда в класс контекста передастся вся конфигурация, не только строка подключения к базе, а хотелось бы чтобы контекст знал и получал только то, что ему нужно
0
Эксперт .NET
 Аватар для Rius
13026 / 7591 / 1662
Регистрация: 25.05.2015
Сообщений: 23,094
Записей в блоге: 14
17.02.2025, 11:16
Через configuration bind получите только нужную ветвь настроек в виде класса и его передайте.
0
3 / 3 / 0
Регистрация: 23.12.2016
Сообщений: 254
17.02.2025, 11:25  [ТС]
Rius, а можно пример? И надо ли создавать отдельный класс, или он как-то автоматом создастся при обращении к конфигурации?
0
Эксперт .NET
 Аватар для Rius
13026 / 7591 / 1662
Регистрация: 25.05.2015
Сообщений: 23,094
Записей в блоге: 14
17.02.2025, 11:32
Пакет Microsoft.Extensions.Configuration.Binde r

JSON
1
2
3
4
5
{
  "ConnectionStrings": {
    "Database": "Data Source=../../data/database.db"
  },
...
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public static class ConfigurationBuilderExtension
{
    public static IServiceCollection AddCustomConfiguration(
        this IServiceCollection serviceCollection,
        string[] args)
    {
        var configuration = CreateConfiguration(args);
        serviceCollection.AddSingleton(configuration);
 
        var appConfig = configuration.Get<AppConfig>() as IAppConfig;
        serviceCollection.AddSingleton(appConfig!);
        serviceCollection.AddSingleton(appConfig.ConnectionStrings);
 
        return serviceCollection;
    }
 
    public static IConfiguration CreateConfiguration(string[] args)
    {
        var configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json")
            .AddJsonFile("appsettings.Development.json", true)
            .AddCommandLine(args)
            .Build();
        return configuration;
    }
}
C#
1
2
3
4
public interface IAppConfig
{
    IConnectionStringsConfig ConnectionStrings { get; }
}
C#
1
2
3
4
5
6
public class AppConfig : IAppConfig
{
    public ConnectionStringsConfig ConnectionStrings { get; } = new ConnectionStringsConfig();
 
    IConnectionStringsConfig IAppConfig.ConnectionStrings => ConnectionStrings;
}
C#
1
2
3
4
public interface IConnectionStringsConfig
{
    string Database { get; }
}
C#
1
2
3
4
public class ConnectionStringsConfig : IConnectionStringsConfig
{
    public string Database { get; init; }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
public class AppDbContext : DbContext
{
    private readonly IConnectionStringsConfig _connectionStringsConfig;
 
    public AppDbContext(
        DbContextOptions<AppDbContext> options,
        IConnectionStringsConfig connectionStringsConfig)
        : base(options)
    {
        _connectionStringsConfig = connectionStringsConfig;
    }
    ...
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
internal class Program
{
    private static void Main(string[] args)
    {
        var serviceProvider = new ServiceCollection()
            .AddCustomConfiguration(args)
            .AddCustomLogger()
            .AddAppDbContext()
            .AddScoped<App>()
            .BuildServiceProvider();
 
        using (var scope = serviceProvider.CreateScope())
        {
            var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
            dbContext.Database.Migrate();
        }
 
        using (var app = serviceProvider.GetService<App>())
        {
            app.Run();
        }
    }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class App : IDisposable
{
    private readonly IAppConfig _appConfig;
    private readonly AppDbContext _dbContext;
    private readonly ILogger<App> _logger;
 
    public App(
        ILogger<App> logger,
        IAppConfig appConfig,
        AppDbContext dbContext)
    {
        _logger = logger;
        _appConfig = appConfig;
        _dbContext = dbContext;
    }
 
    public void Dispose()
    {
        _webDriver.Quit();
    }
 
    public void Run()
    {
        ...
1
3 / 3 / 0
Регистрация: 23.12.2016
Сообщений: 254
17.02.2025, 11:36  [ТС]
Rius, спасибо, буду пробовать
0
 Аватар для Andrey-MSK
3313 / 2200 / 387
Регистрация: 14.08.2018
Сообщений: 7,404
Записей в блоге: 4
17.02.2025, 11:46
Цитата Сообщение от IIIIIIIIIgor Посмотреть сообщение
тогда в класс контекста передастся вся конфигурация, не только строка подключения к базе, а хотелось бы чтобы контекст знал и получал только то, что ему нужно
Он получит только строку подключения, так как вы явно получаете значение
C#
1
_connectionString = _configuration.GetConnectionString("SQLConnectDebug");
А вот сервис конфигурации будет знать всё, и любое другое значение из файла конфигурации можно будет использовать где нужно, а не городить что-то отдельное, если вдруг понадобятся эти значения.
0
3 / 3 / 0
Регистрация: 23.12.2016
Сообщений: 254
17.02.2025, 16:23  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
var appConfig = configuration.Get<AppConfig>() as IAppConfig;
эта строка вызывает ошибку ""IConfiguration" не содержит определения "Get", и не удалось найти доступный метод расширения "Get", принимающий тип "IConfiguration" в качестве первого аргумента (возможно, пропущена директива using или ссылка на сборку)."

в юзингах есть using Microsoft.Extensions.Configuration;
0
 Аватар для Andrey-MSK
3313 / 2200 / 387
Регистрация: 14.08.2018
Сообщений: 7,404
Записей в блоге: 4
17.02.2025, 16:25
IIIIIIIIIgor,
Цитата Сообщение от Andrey-MSK Посмотреть сообщение
если вдруг понадобятся эти значения
Вот пример моих слов для обновления ПО. Значения адреса обновления лежат в файле конфигурации и в вашем случае для их получения пришлось бы городить что-то лишнее...
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
#if DEBUG
    string updatePath = App.Current.Configuration["AppSettings:UpdatesDebugURI"];
#elif RELEASEALFA
    string updatePath = App.Current.Configuration["AppSettings:UpdatesAlfaURI"];
#else
    string updatePath = App.Current.Configuration["AppSettings:UpdatesURI"];
#endif
    string changeLogFile = Path.Combine(updatePath, "ChangeLog.txt");
 
    txtCurrent.Text = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion.Trim();
    txtNew.Text = _updateInfo.Version;
 
    try
    {
        using (StreamReader reader = new StreamReader(changeLogFile))
            txtChangeLog.Text = await reader.ReadToEndAsync();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
    }
}
А так - один сервис и получаем из него что надо в нужных местах.
Цитата Сообщение от IIIIIIIIIgor Посмотреть сообщение
тогда в класс контекста передастся вся конфигурация
В класс ничего не передаётся кроме ссылки на сервис. Вы из сервиса получаете конкретные данные, сам сервис ничего в себе не хранит, кроме адреса файла конфигурации. Читает он оттуда по требованию.
0
3 / 3 / 0
Регистрация: 23.12.2016
Сообщений: 254
17.02.2025, 16:34  [ТС]
Цитата Сообщение от Andrey-MSK Посмотреть сообщение
А так - один сервис и получаем из него что надо в нужных местах.
это разве не является нарушением? ведь контексту нужна только строка подключения, но если он захочет он из конфигурации достанет другие данные что ему в целом то и не нужны
0
 Аватар для Andrey-MSK
3313 / 2200 / 387
Регистрация: 14.08.2018
Сообщений: 7,404
Записей в блоге: 4
17.02.2025, 16:35
Цитата Сообщение от IIIIIIIIIgor Посмотреть сообщение
это разве не является нарушением?
Нарушением чего?
Цитата Сообщение от IIIIIIIIIgor Посмотреть сообщение
но если он захочет он из конфигурации достанет другие данные что ему в целом то и не нужны
Не он захочет, а вы ему разрешите это сделать, написав соответствующий код.
0
3 / 3 / 0
Регистрация: 23.12.2016
Сообщений: 254
17.02.2025, 16:56  [ТС]
Цитата Сообщение от Andrey-MSK Посмотреть сообщение
Нарушением чего?
я ориентировался на этот текст от microsoft
https://learn.microsoft.com/ru... 0%BE%D0%BC.
0
 Аватар для Andrey-MSK
3313 / 2200 / 387
Регистрация: 14.08.2018
Сообщений: 7,404
Записей в блоге: 4
17.02.2025, 17:37
Цитата Сообщение от IIIIIIIIIgor Посмотреть сообщение
я ориентировался на этот текст от microsoft
Дак в чём нарушение-то? Вы читаете один параметр из сервиса, который по запросу читает этот параметр из файла конфигурации...
Там смысл один и тот же...
C#
1
2
3
4
TransientFaultHandlingOptions options = new();
builder.Configuration.GetSection(nameof(TransientFaultHandlingOptions))
    .Bind(options);
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={options.Enabled}");
Добавлено через 2 минуты
Просто в примере читает секцию, а я читаю по имени параметра.

Добавлено через 25 секунд
Просто в примере читает секцию, а я читаю по имени параметра.

Добавлено через 15 минут
IIIIIIIIIgor, Или зайдём с другой стороны. Вы понимаете о чём идёт речь в этой статье и для чего это всё дело используется? Оно вам точно надо? В NET существует очень много разных прибамбасов, которые имеют очень узкоспециализированное применение.

Для вашей задачи достаточно сервиса и чтения оттуда параметра со строкой соединения. Но если хотите усложнить своё приложение, то делайте как в статье, там всё прекрасно расписано.
0
Эксперт .NET
 Аватар для Rius
13026 / 7591 / 1662
Регистрация: 25.05.2015
Сообщений: 23,094
Записей в блоге: 14
17.02.2025, 17:51
Цитата Сообщение от IIIIIIIIIgor Посмотреть сообщение
эта строка вызывает ошибку ""IConfiguration" не содержит определения "Get", и не удалось найти доступный метод расширения "Get", принимающий тип "IConfiguration" в качестве первого аргумента (возможно, пропущена директива using или ссылка на сборку)."
в юзингах есть using Microsoft.Extensions.Configuration;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>
Цитата Сообщение от Rius Посмотреть сообщение
Пакет Microsoft.Extensions.Configuration.Binde r
Добавлено через 3 минуты
C#
1
2
3
4
5
6
7
#if DEBUG
    string updatePath = App.Current.Configuration["AppSettings:UpdatesDebugURI"];
#elif RELEASEALFA
    string updatePath = App.Current.Configuration["AppSettings:UpdatesAlfaURI"];
#else
    string updatePath = App.Current.Configuration["AppSettings:UpdatesURI"];
#endif
Настройки переопределяются самими файлами конфигурации.
А также параметрами запуска, которые можно указать в профиле отладки.
Вот эти ^ макросы не нужны.

C#
1
2
3
4
5
6
7
8
9
10
    public static IConfiguration CreateConfiguration(string[] args)
    {
        var configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json")
            .AddJsonFile("appsettings.Development.json", true)
            .AddCommandLine(args)
            .Build();
        return configuration;
    }
1
 Аватар для Andrey-MSK
3313 / 2200 / 387
Регистрация: 14.08.2018
Сообщений: 7,404
Записей в блоге: 4
17.02.2025, 17:53
Цитата Сообщение от Rius Посмотреть сообщение
Настройки переопределяются самими файлами конфигурации. Вот эти макросы не нужны.
В ASP NET Core да, там файлов несколько. В WPF файл один. Или я что-то пропустил в обновлениях VS?

Добавлено через 1 минуту
Цитата Сообщение от Rius Посмотреть сообщение
C#
1
.AddJsonFile("appsettings.Development.json", true)
Хмммм... Нужно будет поковырять
0
Эксперт .NET
 Аватар для Rius
13026 / 7591 / 1662
Регистрация: 25.05.2015
Сообщений: 23,094
Записей в блоге: 14
17.02.2025, 18:03
Это код вообще из консольной программы.
Никто не мешает добавить файлы и объединить их в одной конфигурации.

Добавлено через 2 минуты
Переопределение параметров через профиль запуска:
launchSettings.json
JSON
1
2
3
4
5
6
7
8
{
  "profiles": {
    "Profile1": {
      "commandName": "Project",
      "commandLineArgs": "--ConnectionStrings:Database=\"Data Source=h:/Prj/Desktop/project1/data/database.db\" "
    }
  }
}
Профилей может быть несколько. Нужный выбирается в выпадающем списке кнопки запуска отладки проекта в Visual Studio.

Добавлено через 6 минут
Цитата Сообщение от IIIIIIIIIgor Посмотреть сообщение
но если он захочет он из конфигурации достанет другие данные что ему в целом то и не нужны
Binder и получение настроек в виде интерфейса хорошо тем, что позволяет передать их куда надо через DI, а также заменить mock'ами в юнит-тестах.
1
 Аватар для IamRain
4693 / 2701 / 734
Регистрация: 02.08.2011
Сообщений: 7,226
17.02.2025, 18:12
Цитата Сообщение от Andrey-MSK Посмотреть сообщение
Нарушением чего?
Типа не видно конкретных зависимостей у типа. Это как передавать IServiceProvider в конструктор (антипаттерн ServiceLocator).

Еще DDD и Clean Architecture диктует правило - делать зависимости более чистыми:
C#
1
2
3
4
5
6
7
8
9
// Это гуд
public MyService(Settings settings) {
   _settings = settings;
}
 
// Это не гуд - зачем в доменной логике ссылка на сборку с типом IOptions<>???
public MySerfvice(IOptions<Settings> options) {
   _settings = options.Value;
}
0
Эксперт .NET
 Аватар для Wolfdp
3789 / 1766 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
17.02.2025, 18:54
Цитата Сообщение от Andrey-MSK Посмотреть сообщение
C#
1
2
3
4
5
#if DEBUG
            _connectionString = _configuration.GetConnectionString("SQLConnectDebug");
#elif RELEASE || RELEASEALFA
            _connectionString = _configuration.GetConnectionString("SQLConnect");
#endif
Правильнее это #if пихать в регистрацию, в остальном -- я бы так и делал.

Добавлено через 11 минут
Цитата Сообщение от IIIIIIIIIgor Посмотреть сообщение
это разве не является нарушением? ведь контексту нужна только строка подключения, но если он захочет он из конфигурации достанет другие данные что ему в целом то и не нужны
Как и для обычных классов, вы можете в IOptions регистрировать интерфейсы, а не классы. Т.е. скажем у вас класс содержит строку подключения и два таймаута для подключения: обычный и для долгих операций. Вы делаете два интерфейса (один с connectionstring, второй с defaultTimeout и longTimeout), класс который содержит всё это и далее при регистрации по идеи будет как-то так

C#
1
2
        serviceCollection.AddSingleton<IConnectionString, DBConfig>(appConfig);
        serviceCollection.AddSingleton<IDBTimeout, DBConfig>(appConfig);
Ещё дополнительно можно атрибуты навешивать, чтобы можно использовать один и тот же интерфес или класс, но при этом в разных частях кода использовались разные значения.

Добавлено через 5 минут
Цитата Сообщение от IamRain Посмотреть сообщение
C#
1
2
3
4
// Это не гуд - зачем в доменной логике ссылка на сборку с типом IOptions<>???
public MySerfvice(IOptions<Settings> options) {
   _settings = options.Value;
}
IOptions придется писать руками, а тут уже готовое Не всегда, но настройки могут храниться в рантайме (скажем стягиваются с сервера и переодически пингуется их обновление). В коде где нужно использовать эти настройки нужно запоминать именно провайдер, а IOptions -- именно этот интерфейс.

Если рассматривать "стартануло - ситало - не меняется", действительно выглядит избыточно.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
17.02.2025, 18:54
Помогаю со студенческими работами здесь

Необходимо реализовать структуру данных (стек строк) в виде класса или набора классов, не используя стандартные классы
Здравствуйте! Помогите пожалуйста разобраться с поставленной задачей. Необходимо реализовать структуру данных (стек строк) в виде класса...

Реализовать структуру данных «очередь строк» в виде класса
Реализовать структуру данных «очередь строк» в виде класса (набора классов). Стандартные классы-коллекции .NET не использовать, в качестве...

Regex: Создать регулярное выражения для поиска строк вида: "add -s 50 -k 20".
Нужно создать регулярное выражения для поиска строк вида: &quot;add -s 50 -k 20&quot;. При этом надо, чтобы он искал все -s и -k и другие буквы. То...

Сделать видимыми номера строк в коде
как сделать видимыми номера строк в коде?

Программирование с использованием строк (обычный вариант и с использованием 3 видов строк
Даны строки S1, S2 и символ C. Перед (после) каждого вхождения символа C в строку S1 вставить строку S2.


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru