You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨Azure账户的Timer触发器Azure Functions配置Entity Framework Core连接Azure SQL故障求助

问题描述

我在一个Azure账户中拥有Azure SQL数据库,另一个Azure账户部署了Timer触发器类型的Azure Functions。已经用Entity Framework Core完成数据库映射,但执行查询操作时无法正常工作,推测是配置存在问题。尝试多种解决方案仍未解决,现附上相关代码文件及运行错误信息,希望能得到帮助,提前感谢!


代码文件

Function1.cs

using System;
using System.Data.SqlClient;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Text;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Microsoft.Azure.Functions.Extensions;
using Microsoft.Net.Http;
using Microsoft.EntityFrameworkCore.SqlServer.Design;
using Microsoft.EntityFrameworkCore.SqlServer;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using Newtonsoft.Json;

namespace azuretosharepoint
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task RunAsync([TimerTrigger("0 */1 * * * *")] TimerInfo myTimer, ILogger log)
        {
            var azsh = new ProgettokpidatabaseContext();
            var listsharepoint = azsh.KpiTables.ToList();
            Console.WriteLine(listsharepoint);
        }
    }
}

progettokpidatabaseContext.cs

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Design;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
#nullable disable

namespace azuretosharepoint
{
    public partial class ProgettokpidatabaseContext : DbContext
    {
        public ProgettokpidatabaseContext()
        {
        }

        public ProgettokpidatabaseContext(DbContextOptions<ProgettokpidatabaseContext> options)
            : base(options)
        {
        }

        public virtual DbSet<KpiTable> KpiTables { get; set; }
        public virtual DbSet<KptKpiTarget> KptKpiTargets { get; set; }
        public virtual DbSet<KpvKpiValue> KpvKpiValues { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
//optionsBuilder.UseSqlServer("Server=tcp:progetto-kpi.database.windows.net,1433;Initial Catalog=progetto-kpi-database;Persist Security Info=False;User ID=progetto-kpi;Password=**********;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;");
                optionsBuilder.UseSqlServer(Environment.GetEnvironmentVariable("sqlconnectionstring"));
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.HasAnnotation("Relational:Collation", "SQL_Latin1_General_CP1_CI_AS");

            modelBuilder.Entity<KpiTable>(entity =>
            {
                entity.HasKey(e => e.KpiId);

                entity.ToTable("KPI_table");

                entity.Property(e => e.KpiId)
                    .ValueGeneratedNever()
                    .HasColumnName("KPI_ID");

                entity.Property(e => e.KpiBusinessArea)
                    .IsRequired()
                    .HasMaxLength(50)
                    .HasColumnName("KPI_Business_Area");

                entity.Property(e => e.KpiDescription)
                    .HasMaxLength(250)
                    .HasColumnName("KPI_Description");

                entity.Property(e => e.KpiDoi)
                    .HasColumnType("datetime")
                    .HasColumnName("KPI_DOI")
                    .HasDefaultValueSql("(getdate())");

                entity.Property(e => e.KpiDou)
                    .HasColumnType("datetime")
                    .HasColumnName("KPI_DOU")
                    .HasDefaultValueSql("(getdate())");

                entity.Property(e => e.KpiFrequency)
                    .HasMaxLength(10)
                    .HasColumnName("KPI_Frequency");

                entity.Property(e => e.KpiManual).HasColumnName("KPI_Manual");

                entity.Property(e => e.KpiName)
                    .IsRequired()
                    .HasMaxLength(50)
                    .HasColumnName("KPI_Name");
            });

            modelBuilder.Entity<KptKpiTarget>(entity =>
            {
                entity.HasKey(e => e.KptId)
                    .HasName("PK_KPT_table");

                entity.ToTable("KPT_KPI_Targets");

                entity.Property(e => e.KptId)
                    .ValueGeneratedNever()
                    .HasColumnName("KPT_ID");

                entity.Property(e => e.KptDate)
                    .HasColumnType("date")
                    .HasColumnName("KPT_Date");

                entity.Property(e => e.KptDoi)
                    .HasColumnType("datetime")
                    .HasColumnName("KPT_DOI")
                    .HasDefaultValueSql("(getdate())");

                entity.Property(e => e.KptDou)
                    .HasColumnType("datetime")
                    .HasColumnName("KPT_DOU")
                    .HasDefaultValueSql("(getdate())");

                entity.Property(e => e.KptKpiId).HasColumnName("KPT_KPI_ID");

                entity.Property(e => e.KptTarget)
                    .HasColumnType("decimal(18, 2)")
                    .HasColumnName("KPT_Target");

                entity.HasOne(d => d.KptKpi)
                    .WithMany(p => p.KptKpiTargets)
                    .HasForeignKey(d => d.KptKpiId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK__KPT_KPI_T__KPT_K__2FCF1A8A");
            });

            modelBuilder.Entity<KpvKpiValue>(entity =>
            {
                entity.HasKey(e => e.KpvId)
                    .HasName("PK_KPV_table");

                entity.ToTable("KPV_KPI_Values");

                entity.Property(e => e.KpvId)
                    .ValueGeneratedNever()
                    .HasColumnName("KPV_ID");

                entity.Property(e => e.KpvDate)
                    .HasColumnType("date")
                    .HasColumnName("KPV_Date");

                entity.Property(e => e.KpvDoi)
                    .HasColumnType("datetime")
                    .HasColumnName("KPV_DOI")
                    .HasDefaultValueSql("(getdate())");

                entity.Property(e => e.KpvDou)
                    .HasColumnType("datetime")
                    .HasColumnName("KPV_DOU")
                    .HasDefaultValueSql("(getdate())");

                entity.Property(e => e.KpvKpiId).HasColumnName("KPV_KPI_ID");

                entity.Property(e => e.KpvValue)
                    .HasColumnType("decimal(18, 2)")
                    .HasColumnName("KPV_Value");

                entity.HasOne(d => d.KpvKpi)
                    .WithMany(p => p.KpvKpiValues)
                    .HasForeignKey(d => d.KpvKpiId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK__KPV_KPI_V__KPV_K__3587F3E0");
            });

            OnModelCreatingPartial(modelBuilder);
        }

        partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
    }
}

local.settings.json

{
  "IsEncrypted": false,
  "AzureWebJobsStorage": "UseDevelopmentStorage=true",
  "FUNCTIONS_WORKER_RUNTIME": "dotnet",
  "Values": {
    "sqlconnectionstring": "Server=tcp:progetto-kpi.database.windows.net,1433;Initial Catalog=progetto-kpi-database;Persist Security Info=False;User ID=progetto-kpi;Password=*********;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;",
    "ProviderName": "System.Data.SqlClient"
  }
}

azuretosharepoint.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <AzureFunctionsVersion>v3</AzureFunctionsVersion>
    <UserSecretsId>4e8db286-9c45-4574-b556-eb0a04ac345e</UserSecretsId>
    <OutputType>Library</OutputType>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Dapper" Version="2.0.90" />
    <PackageReference Include="Dapper.Contrib" Version="2.0.78" />
    <PackageReference Include="Dapper.FluentMap" Version="2.0.0" />
    <PackageReference Include="Dapper.SimpleCRUD" Version="2.3.0" />
    <PackageReference Include="EntityFramework" Version="6.4.4" />
    <PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.18.0-beta1" />
    <PackageReference Include="Microsoft.AspNetCore.AzureKeyVault.HostingStartup" Version="2.0.4" />
    <PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.1">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="2.0.0-preview1-final" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.1">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="3.1.10" />
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.12" />
    <PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0-preview.4.21253.7" />
    <PackageReference Include="System.Data.Common" Version="4.3.0" />
    <PackageReference Include="System.Data.SqlClient" Version="4.8.2" />
    <PackageReference Include="System.IO" Version="4.3.0" />
    <PackageReference Include="System.Linq" Version="4.3.0" />
    <PackageReference Include="System.Runtime" Version="4.3.1" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
  <ItemGroup>
    <Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
  </ItemGroup>
</Project>

运行错误信息

Azure Functions Core Tools
Core Tools Version: 3.0.3568 Commit hash: e30a0ede85fd498199c28ad699ab2548593f759b (64-bit)
Function Runtime Version: 3.0.15828.0
Can't determine project language from files. Please use one of [--csharp, --javascript, --typescript, --java, --python, --powershell, --custom]
Missing value for AzureWebJobsStorage in local.settings.json. This is required for all triggers other than httptrigger, kafkatrigger, rabbitmqtrigger, orchestrationTrigger, activityTrigger, entityTrigger. You can run 'func azure functionapp fetch-app-settings <functionAppName>' or specify a connection string in local.settings.json.

解决方案

1. 修复local.settings.json结构错误

你的配置文件结构不符合Azure Functions的要求,AzureWebJobsStorage和FUNCTIONS_WORKER_RUNTIME必须放在Values节点下,否则运行时无法读取这些核心配置。修改后的正确结构如下:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "sqlconnectionstring": "Server=tcp:progetto-kpi.database.windows.net,1433;Initial Catalog=progetto-kpi-database;Persist Security Info=False;User ID=progetto-kpi;Password=*********;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;",
    "ProviderName": "System.Data.SqlClient"
  }
}

2. 正确通过依赖注入获取连接字符串

Azure Functions中,直接使用Environment.GetEnvironmentVariable可能无法正确读取local.settings.json中的配置(尤其是本地调试场景)。建议通过依赖注入IConfiguration来读取连接字符串,同时重构DbContext的配置方式:

修改DbContext构造函数

public partial class ProgettokpidatabaseContext : DbContext
{
    private readonly IConfiguration _configuration;

    public ProgettokpidatabaseContext(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public ProgettokpidatabaseContext(DbContextOptions<ProgettokpidatabaseContext> options, IConfiguration configuration)
        : base(options)
    {
        _configuration = configuration;
    }

    // 保留原有的DbSet和OnModelCreating代码...

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            optionsBuilder.UseSqlServer(_configuration["sqlconnectionstring"]);
        }
    }
}

修改Function使用依赖注入

将静态函数改为实例类,通过构造函数注入DbContext,同时使用ILogger替代Console.WriteLine(Functions推荐使用日志组件输出信息):

namespace azuretosharepoint
{
    public class Function1
    {
        private readonly ProgettokpidatabaseContext _dbContext;

        public Function1(ProgettokpidatabaseContext dbContext)
        {
            _dbContext = dbContext;
        }

        [FunctionName("Function1")]
        public async Task RunAsync([TimerTrigger("0 */1 * * * *")] TimerInfo myTimer, ILogger log)
        {
            var listsharepoint = await _dbContext.KpiTables.ToListAsync();
            log.LogInformation($"成功获取{listsharepoint.Count}条KPI记录");
        }
    }
}

3. 修复EF Core与.NET Core版本不兼容问题

你的项目目标框架是.netcoreapp3.1,但使用的EF Core版本是5.0.1——这两个版本不兼容(EF Core 5.x对应.NET 5.0)。你有两个选择:

  • 升级项目框架:将csproj中的<TargetFramework>改为net5.0,适配EF Core 5.x:
    <TargetFramework>net5.0</TargetFramework>
    
  • 降级EF Core版本:将所有EF Core相关包降级到3.1.x系列,确保版本一致,例如:
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.20" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.20">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.20" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.20" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.20">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    

4. 解决项目语言识别问题

如果仍然出现Can't determine project language from files提示,运行Functions Core Tools时可以手动指定语言参数:

func start --csharp

内容的提问来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 17:57:39